Stack Overflowでこれに似た質問が何度も繰り返されることを知っていますが、重複するタプルをリストから削除する必要がありますが、要素が一致する場合だけでなく、要素は同じ順序である必要があります。言い換えると、 (4,3,5)
および(3,4,5)
は両方とも出力に存在しますが、両方がある場合は(3,3,5)
および(3,3,5)
、1つだけが出力されます。
具体的には、私のコードは:
import itertools
x = [1,1,1,2,2,2,3,3,3,4,4,5]
y = []
for x in itertools.combinations(x,3):
y.append(x)
print(y)
このうち、出力はかなり長くなります。たとえば、出力では、両方の(1,2,1)
および(1,1,2)
。ただし、存在するのは1つだけです(1,2,2)
。
set
はそれを処理します:
>>> a = [(1,2,2), (2,2,1), (1,2,2), (4,3,5), (3,3,5), (3,3,5), (3,4,5)]
>>> set(a)
set([(1, 2, 2), (2, 2, 1), (3, 4, 5), (3, 3, 5), (4, 3, 5)])
>>> list(set(a))
[(1, 2, 2), (2, 2, 1), (3, 4, 5), (3, 3, 5), (4, 3, 5)]
>>>
set
はexactの重複のみを削除します。
必要なのは、組み合わせではなく一意の順列です。
_y = list(set(itertools.permutations(x,3)))
_
つまり、(1,2,2)と(2,1,2)は同じ組み合わせと見なされ、そのうちの1つだけが返されます。ただし、それらは異なる順列です。重複を削除するには、set()
を使用します。
その後、各タプル内の要素を並べ替え、リスト全体も並べ替えたい場合は、次のようにします。
_y = [Tuple(sorted(q)) for q in y]
y.sort()
_
for
ループを実行する必要はありません。combinations
はジェネレーターを提供します。
x = [1,1,1,2,2,2,3,3,3,4,4,5]
y = list(set(itertools.combinations(x,3)))
これはおそらくあなたが望むことをするでしょうが、それは非常に過剰です。 mayがitertools
にいつか追加されるジェネレータの低レベルのプロトタイプです。 Cでの再実装を容易にするのは低レベルです。N
は反復可能な入力の長さで、最悪の場合のスペースO(N)
を必要とし、最大でN*(N-1)//2
要素を必要とします生成されるアナグラムの数に関係なく、比較。どちらも最適です;-)
次のように使用します。
>>> x = [1,1,1,2,2,2,3,3,3,4,4,5]
>>> for t in anagrams(x, 3):
... print(t)
(1, 1, 1)
(1, 1, 2)
(1, 1, 3)
(1, 1, 4)
(1, 1, 5)
(1, 2, 1)
...
出力に重複はありません。注:これはPython 3コードです。Python 2.で実行するには、いくつかの変更が必要です。
import operator
class ENode:
def __init__(self, initial_index=None):
self.indices = [initial_index]
self.current = 0
self.prev = self.next = self
def index(self):
"Return current index."
return self.indices[self.current]
def unlink(self):
"Remove self from list."
self.prev.next = self.next
self.next.prev = self.prev
def insert_after(self, x):
"Insert node x after self."
x.prev = self
x.next = self.next
self.next.prev = x
self.next = x
def advance(self):
"""Advance the current index.
If we're already at the end, remove self from list.
.restore() undoes everything .advance() did."""
assert self.current < len(self.indices)
self.current += 1
if self.current == len(self.indices):
self.unlink()
def restore(self):
"Undo what .advance() did."
assert self.current <= len(self.indices)
if self.current == len(self.indices):
self.prev.insert_after(self)
self.current -= 1
def build_equivalence_classes(items, equal):
ehead = ENode()
for i, elt in enumerate(items):
e = ehead.next
while e is not ehead:
if equal(elt, items[e.indices[0]]):
# Add (index of) elt to this equivalence class.
e.indices.append(i)
break
e = e.next
else:
# elt not equal to anything seen so far: append
# new equivalence class.
e = ENode(i)
ehead.prev.insert_after(e)
return ehead
def anagrams(iterable, count=None, equal=operator.__eq__):
def perm(i):
if i:
e = ehead.next
assert e is not ehead
while e is not ehead:
result[count - i] = e.index()
e.advance()
yield from perm(i-1)
e.restore()
e = e.next
else:
yield Tuple(items[j] for j in result)
items = Tuple(iterable)
if count is None:
count = len(items)
if count > len(items):
return
ehead = build_equivalence_classes(items, equal)
result = [None] * count
yield from perm(count)
あなたは本当に親しかった。組み合わせではなく順列を取得するだけです。順序は順列で重要であり、組み合わせではありません。したがって、(1、2、2)は(2、2、1)とは異なる順列です。ただし、(1、2、2)は、1 1と2 2の1つの組み合わせと見なされます。したがって、(2、2、1)は(1、2、2)とは異なる組み合わせとは見なされません。
リストyをセットに変換して、重複を削除することができます...
import itertools
x = [1,1,1,2,2,2,3,3,3,4,4,5]
y = []
for x in itertools.permutations(x,3):
y.append(x)
print(set(y))
これで出来上がりです。 :)
set の使用はおそらく機能するはずです。セットは基本的に、重複する要素を含まないコンテナです。
Pythonには、セットのデータ型も含まれています。セットは、重複する要素がない順序付けられていないコレクションです。基本的な用途には、メンバーシップテストや重複エントリの排除が含まれます。セットオブジェクトは、ユニオン、インターセクション、差分、対称差分などの数学演算もサポートしています。
import itertools
x = [1,1,1,2,2,2,3,3,3,4,4,5]
y = set()
for x in itertools.combinations(x,3):
y.add(x)
print(y)