Pythonのリスト内包表記でRubyのuniqメソッドと同じ事をする

動機

設定値の重複を削るためににスクリプトを組んだのだけど、Pythonだとループで回して新しい配列に突っ込んでとかやらないといけないっぽいので面倒臭いエレガントじゃない。

一応Pythonで単純に書くと以下のようなコードになると思います。

a = [1,3,4,2,3,5]
b = []
for v in a:
    if v not in b:
        b.append(v)
print b # [1, 3, 4, 2, 5]

RubyはArray.uniqを作った

そんなこんなでRubyだとuniqという重複を取り除くメソッドがあるのでこちらを使って処理しました。
コードは

[1,3,4,2,3,5].uniq # [1, 3, 4, 2, 5]

で、どう見てもこっちの方がエレガントです。

一方Pythonでは

listから重複削除というのはどうも無いらしくlist→set→listへキャストすれば重複削れるよという記事があったものの順序までは維持できないので却下。

一応コード。

a = [1,3,4,2,3,5]
print list(set(a)) # [1, 2, 3, 4, 5]

やっぱりPythonicにリスト内包表記

ループ中に簡単な処理書くだけならリスト内包表記で書けるはずだ!ということで20分ぐらいねばった結果出来た。

a = [1,3,4,2,3,5]
print [y for x,y in enumerate(a) if a[:x+1].count(y) == 1] # [1, 3, 4, 2, 5]

何をしているかというと

for x,y in enumerate(a)

ここでリストのインデックスと要素を取り出し、

a[:x+1]

ここでforで回してる配列のインデックスのところまでの配列を切りだし、

if a[:x+1].count(y) == 1

切りだしたリストに要素の中身の数が1だったら、つまり重複が無ければ、新しいリストに追加
と言うことをしています。

結論

Python信者の自分からからみてもRubyの方が綺麗だと思います。
もしくは自分のリスト内包表記のレベルが足りないのか。
せめて内包表記の中で自分を示す予約語的なものがあればいいんだけどなあ・・・
イメージとしてはこんな感じ。

print [x for x in a if x not in self]

ということで、PyチューやエキPyを参考にもうちょっとエレガントなコードを目指す。
リスト内包表記はワンライナー表記と変わらんので突っ込みすぎると逆にクソコード化する諸刃の剣。
なので程々にゆるりと・・・

忘れてましたが

今年の目標達成まで残り50個