python’s unique list (with order preserved) part II

せっかくなのでこっちの話も。

UNIX コマンドの uniq の振る舞い:

 1 me@host: ~$ printf "aaa\naaa\nbbb\naaa\n"
 2 aaa
 3 aaa
 4 bbb
 5 aaa
 6 me@host: ~$ printf "aaa\naaa\nbbb\naaa\n" | uniq
 7 aaa
 8 bbb
 9 aaa
10 me@host: ~$ printf "aaa\naaa\nbbb\naaa\n" | sort | uniq
11 aaa
12 bbb

これはつまり、「連続する重複」を取り除くものなんだね、uniq は。

まさにこれをしたい場合もあるはず。いわゆる「履歴」なんてことを実現するためにしたいのはこういうことだろう。

「あとから削除」としては stackoverflow のこの回答でいいと思う。これをさっきの uniq_list みたいにしたいとしたら? うー、思ったより頭ひねるので面倒なのでやらない。今のワタシのニーズにはないし。ほんとに必要になったら書こうと思う。


2017-08-15追記:
必要になっちゃった。というか「必要ってほどでもないんだけれども偏執狂的に」と言ったほうが近いか。

insert は考えるの面倒でひとまず not impl にしちゃってるけどまぁこんなだろうね:

ハイライト部分は 2017-09-01 追加
 1 # -*- coding: utf-8 -*-
 2 from __future__ import unicode_literals
 3 
 4 
 5 from itertools import groupby
 6 
 7 
 8 class _compact_list(list):
 9     """
10     We can not get rid of the parameters to the compilers
11     just because they are duplicated. This is because the
12     users of the compilers expect to overwrite definitions
13     and so on according to the order of designation, and
14     the compilers also allow it. Also, due to dependency
15     ordering, there are even libraries that need to be doubly
16     specified on the command line. For example, if library B
17     depends on library A and your application depends on
18     them you may have to direct "A.lib B.lib A.lib" on
19     the command line.
20 
21     However, it is safe to remove the same items as the
22     previous item. Such duplication is meaningless and
23     redundant for both users and compilers.
24 
25     This class is a list, but it doesn't append such
26     duplicated items:
27 
28     >>> clist = _compact_list()
29     >>> clist.append(2)
30     >>> clist
31     [2]
32     >>> clist.append(2)
33     >>> clist
34     [2]
35     >>> _compact_list([1, 1, 2])
36     [1, 2]
37     >>> clist = _compact_list()
38     >>> clist.extend(range(5))
39     >>> clist
40     [0, 1, 2, 3, 4]
41     >>> clist = _compact_list()
42     >>> clist.extend([3, 3, 4, 4, 3, 3])
43     >>> clist
44     [3, 4, 3]
45     >>> clist = _compact_list([1, 1, 2])
46     >>> clist
47     [1, 2]
48     >>> clist.append(2)
49     >>> clist
50     [1, 2]
51     >>> clist.append(3)
52     >>> clist
53     [1, 2, 3]
54     >>> clist.extend([3, 4, 4, 5])
55     >>> clist
56     [1, 2, 3, 4, 5]
57     >>> clist.extend([])
58     >>> clist
59     [1, 2, 3, 4, 5]
60     >>> clist = _compact_list()
61     >>> clist.extend([])
62     >>> clist.extend([1])
63     >>> clist
64     [1]
65     >>> clist.extend([1])
66     >>> clist
67     [1]
68     """
69     def __init__(self, seq=[]):
70         if seq:
71             list.__init__(
72                 self, [x[0] for x in groupby(seq)])
73         else:
74             list.__init__(self)
75 
76     def append(self, item):
77         if not self or (len(self) > 0 and self[-1] != item):
78             list.append(self, item)
79 
80     def insert(self, idx, item):
81         raise NotImplementedError()
82 
83     def extend(self, seq):
84         if seq:
85             seq = [x[0] for x in groupby(seq)]
86             idx = 0
87             if len(self) > 0:
88                 while self[-1] == seq[idx]:
89                     idx += 1
90                     if idx == len(seq):
91                         break
92             list.extend(self, seq[idx:])
93 
94 
95 if __name__ == '__main__':
96     import doctest
97     doctest.testmod()

なお、「英語がわからん」からといって、コピペ時にこれをそのままコピペするなよ。恥ずかしいぞ。だってこれは「アタシの事情」を書いているんであるからして。