uniq()あれこれ
ふとこちらの記事を拝見して、頭に浮かんだことをメモってみる。
[y for x,y in enumerate(seq) if seq[:x+1].count(y) == 1]
や、id:cocoatomoさんの
[x for i, x in enumerate(a) if i == a.index(x)]
でも良いんだけど、あえて別解を探すと:
Python2.7/3なら
import collections list(collections.OrderedDict((x,None) for x in seq).keys())
一番素直で速いのは
filter(lambda x,s=set():(x not in s, s.add(x))[0], seq)
かなぁ?
入力のリストの要素から、新たな一つのリストに還元すると考えれば、reduce
を使う手もある。
reduce( lambda x, y, s=set(): (x+[y], s.add(y))[0] if y not in s else x, seq, [])
毎回新しいリストオブジェクト作って中身をコピーしてるから、O(N2)
だ?気になるんだったらreduce
は使えないねぇ。それともリスト内包で
[x for i, x in enumerate(seq) if x not in seq[:i]]
毎回リストオブジェクトを作るのは嫌?それなら
from itertools import repeat [x for x, s in zip(seq, repeat(set())) if (x not in s) and (s.add(x) or True)]
かなぁ。
こっちの方が綺麗か
from itertools import repeat [(s.add(x) or x) for x, s in zip(seq, repeat(set())) if x not in s]
でもまぁ、なんだかんだ言っても、素直に
def uniq(seq): seen = set() for i in seq: if i not in seen: yield i seen.add(i)
が一番。素直が一番だ。itertools.uniq()
とかはあっても良い気はするけど、あんまりニーズないのかな?