リストの一部だけソートしたくなったので、その時の覚書を残します。
とある2次元配列のリストをある特定の幅で区切って、その幅だけソートする。配列の部分ソート。基本的にはsort()ないしsorted()関数を使ってリストのソートをするのですが、ちょっと思った動きをしませんでした。
例えば、画像のある四角形の4頂点のx,y座標が入っているリストを左上からラスタ順(左上、右上、左下、右下)の順に並び替える。そんなシチュエーション。sort/sorted関数の詳細はここでは割愛。具体的には
l2d = [[1,42],[0,32],[100,31],[102,41]]
こんな感じのリストを最終的には、
l2d = [[0,32],[100,31],[1,42],[102,41]]
にしたいと思った時どうするか。です。2個単位で見ると、x座標(0,100 / 1,102)でソートされ、全体はy座標で2分されています。
直感的に、最初にやった記述ですが、
l2d.sort(key=lambda x:x[1]) #y座標でソート #[[100,31],[0,32],[102,41],[1,42]] l2d[0:2].sort(key=lambda x:x[0]) #2要素だけx座標でソート #[[0,32],[100,31],[102,41],[1,42]] l2d[2:4].sort(key=lambda x:x[0]) #2要素だけx座標でソート #[[0,32],[100,31],[1,42],[102,41]]
これでうまくいくことを期待したのですが、どうもスライスさせたリストに対して、sort()が機能しておらず、最初のy座標ソートした結果から変化しませんでした。 2回目、3回目のソートでは変化なし。
スライスさせたリストは別オブジェクト扱いされているのかな。文法的にはエラーになってはいません。
なので、今度はsortedを使いました。
l2d.sort(key=lambda x:x[1]) #y座標でソート #[[100,31],[0,32],[102,41],[1,42]] l2d[0:2] = sorted(l2d[0:2],key=lambda x:x[0]) #2要素だけx座標でソート #[[0,32],[100,31],[102,41],[1,42]] l2d[2:4] = sorted(l2d[2:4],key=lambda x:x[0]) #2要素だけx座標でソート #[[0,32],[100,31],[1,42],[102,41]]
これであればうまく行きました。sortに渡す関数(今回はlambda)とか工夫すればできるのかもしれませんが、イマイチいいのが思いつきません。ソートのやり方が最初と後で違う点少しダサいですが、目的は達成できました。
スライスされたリストを、完全にオリジナルのリストと同じ扱いはできないことをひとまず学びました。少しはまったのでメモを残しておきます。もっとクールな書き方があるかもしれませんが。
コメント