python’s unique list (with order preserved)

何度必要になっても自作するのは容易な…。

調べるのが面倒だ、とかではなくて、「書くのは造作ない」のであえて毎度調べないヤツ。

なお、このトピックには類似品が何種類かあって、

  1. リストから重複を取り除きたい
  2. リストから順序を維持したまま重複を取り除きたい
  3. そもそも既知なら入れてくれるなよリストちゃん
  4. 順序付け集合がほしーの

4. については、さっきPYTHON TIPS経由でSortedContainersを知った。これでないのは前に見たことがあった(Cython プロジェクトだったはず)。探せば結構見つかると思うし、順序付け辞書なら標準ライブラリにもいる。

1. は FAQ でも紹介されてた気がする。これだけ:

1 >>> list(set(["zzz", "aaa", "bbb", "aaa", "aaa", "123"]))
2 ['123', 'aaa', 'zzz', 'bbb']

ご覧の通り順序を維持出来ないために 2.、4. のニーズが生じる。

2. と 3. はほぼ同じことで、3. は「だったら突っ込まなきゃいい、入ってれば」という発想を逆にしただけのもの。これが出来合いのものであるのかないのかを毎度探さない、という話。結構頻繁に必要になるんだけどね…。

まぁこれだけのことなのよ:

 1 class uniq_list(list):
 2     def _notin(self, seq):
 3         for e in seq:
 4             if e not in self:
 5                 yield e
 6 
 7     def __init__(self, initialseq=[]):
 8         list.__init__(self)
 9         if initialseq:
10             self.extend(initialseq)
11 
12     def append(self, e):
13         if e not in self:
14             list.append(self, e)
15 
16     def extend(self, seq):
17         list.extend(self, self._notin(seq))

一致判定を変えることが出来るようにしたりとか多少の発展性はあるかな(case insensitive とか)。それとこれは「既にいれば入れない」ノリだけれど、「後から入れたい方」が順序として正の場合もあるでしょ、例えば「aaa, bbb」に aaa を突っ込みたい場合に「aaa, bbb」ではなく「bbb, aaa」にしたい、とか。そんなわけでそれなりに変種はあると思う。


2017-08-15追記:
part II の追記を書いてて気付いた。上の、insert が抜けてら。ま、自分で書ける…よね?