2014-04-29 17 views
8

Jak mogę uniquify następującą listę w Pythonie:Uzyskaj listę unikalnych wielu zestawów

all_the_ways = [(5,), (2, 2, 1), (2, 1, 2), (2, 1, 1, 1), (1, 2, 2),\ 
       (1, 2, 1, 1), (1, 1, 2, 1), (1, 1, 1, 2), (1, 1, 1, 1, 1)] 

Pożądany wyjścia:

[(5,), (2, 2, 1), (2, 1, 1, 1), (1, 1, 1, 1, 1)] 

czyli muszę pozbyć krotek, które mają takie same zestaw liczb, ale w innej kolejności.

Próbowałem

set(all_the_ways) 

ale tylko transpozycja elementów.

I kiedy zrobić

list(map(set, all_the_ways)) 

rzeczy tylko coraz gorzej:

[{5}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1}] 

Innymi słowy muszę konwertować wewnętrzną krotki do kolekcji, która pozwala kilku równych elementów (set nie jest odpowiedni) i dla których permutacje elementów nie zmieniają samej kolekcji (trochę jak C++ 's multiset)

+0

Co powinno być wyjście kiedy 'all_the_ways = [(2, 1, 2), (2, 2, 1)]'? – thefourtheye

+0

pierwsza lub druga krotka, nie ma znaczenia – tsionyx

+0

Więc wynik powinien być w 'all_the_ways'? – thefourtheye

Odpowiedz

5

Jak o tym:

list(set(tuple(sorted(s)) for s in all_the_ways)) 

wyjściowa:

[(1, 2, 2), (5,), (1, 1, 1, 1, 1), (1, 1, 1, 2)] 

Będzie magiel kolejność każdej krotki chociaż. Zakładam, że to nie ma znaczenia, ponieważ krotki zawierające ten sam zestaw liczb są uważane za takie same dla twojego przypadku. Co oznacza to, że w końcu, lista wyjściowa może zawierać krotki, które nie należą do pierwotnego wejścia, na przykład (kredyt do @thefourtheye):

all_the_ways = [(2, 1, 2), (2, 2, 1)] 
# Output: [(1, 2, 2)] 

To może lub nie może być problemem, a jeśli można użyć bardziej niezawodnych rozwiązań, o których już wspominano w innych znakomitych odpowiedziach.

+1

Jeśli kombinacja '(1, 2, 2)' nie istnieje w 'all_the_ways', może to być problem. Ale nie jestem pewien, czy to jest w porządku z OP. Już + 1ed – thefourtheye

+0

To prawda, o czym wspomniałem w odpowiedzi. Postanowiłem nie zajmować się kwestią zamawiania, aby zapewnić prostszą perspektywę, na wypadek gdyby nie było to ograniczenie w tym problemie. + 1s do wszystkich rozwiązań zabezpieczających zamówienie! :) –

+1

Właściwie to nie chodzi o zamówienie. Gdy 'all_the_ways = [(2, 1, 2), (2, 2, 1)], wyjście będzie miało postać' [(1, 2, 2)] ', którego nie ma w' all_the_ways'. To może być problem, tak myślę. – thefourtheye

0

Uważam, że dwa elementy są "równe", jeśli zawierają te same wartości, niezależnie od kolejności.

Więc może „canonicalize” każda krotka sortując ją przekształcić z powrotem do krotek (a więc są hashable) i usunąć duplikaty używając set ponownie:

set(tuple(sorted(tup)) for tup in all_the_ways) 

Można również zachować oryginalne „zewnętrzny” zamówienie, używając OrderedSet zamiast set.

3

Zastosowanie collections.Counter() zidentyfikować unikalne multisets:

>>> from collections import Counter 

>>> all_the_ways = [(5,), (2, 2, 1), (2, 1, 2), (2, 1, 1, 1), (1, 2, 2),\ 
       (1, 2, 1, 1), (1, 1, 2, 1), (1, 1, 1, 2), (1, 1, 1, 1, 1)] 
>>> result = [] 
>>> seen = set() 
>>> for tup in all_the_ways: 
     key = tuple(sorted(Counter(tup).items())) # unique signature 
     if key not in seen: 
      result.append(tup) 
     seen.add(key) 

>>> result 
[(5,), (2, 2, 1), (2, 1, 1, 1), (1, 1, 1, 1, 1)] 
+0

Myślałem o to tylko, ale nie może przejść dalej, ponieważ nie są one zgodne z haseł ... :( – thefourtheye

+0

@ thefourtheye Po obliczeniu, sortowanie elementów sprawia kanoniczne porządkowanie, a tuplizing sprawia, że ​​jest to możliwe :-) –

+0

Dlaczego nie po prostu? Counter (tuple (posortowane (i)) dla i we all_the_ways) .keys() '? –

1

może być to?:

result = {tuple(sorted(x)) for x in all_the_ways} 
2

Jeśli zamówienie nie ma znaczenia, można użyć tej

from collections import Counter 
>>> {frozenset(Counter(tup).items()):tup for tup in data}.values() 
# [(1, 2, 2), (1, 1, 1, 2), (1, 1, 1, 1, 1), (5,)] 

Jeśli chcesz zachować porządek,

from collections import Counter, OrderedDict 
OrderedDict([frozenset(Counter(tup).items()),tup] for tup in data).values() 
# [(5,), (1, 2, 2), (1, 1, 1, 2), (1, 1, 1, 1, 1)] 

W obu rozwiązaniach możemy liczyć na frozenset, ponieważ obiekty set nie są nieaktualne, ponieważ można je zmieniać. W pierwszym przypadku konstruujemy słownik z częstotliwością liczb (określaną jako Counter) jako kluczem i bieżącą krotką jako wartością odpowiadającą temu. Po zakończeniu budowy słownika, przyjmujemy wszystkie wartości, które odpowiadają krotkom.

W drugim przypadku po prostu używamy OrderedDict, aby utrzymać zamówienie.

+1

+1 Za ładne połączenie OrderedDict, frozenset i Counter. –

+0

@RaymondHettinger Dziękuję :-) – thefourtheye

1

Spróbuj

from collections import OrderedDict 
print OrderedDict.fromkeys(map(lambda x: tuple(sorted(x)), all_the_ways)).keys() 

lub

print set(map(lambda x: tuple(sorted(x)), all_the_ways)) 
Powiązane problemy