2010-09-24 17 views
55

W niektórych z moich kodów umieszczam serię obiektów na liście i buduję dodatkową listę z ich atrybutów, która jest łańcuchem. Muszę ustalić, czy wszystkie elementy na tej drugiej liście mają dokładnie taką samą wartość, nie wiedząc wcześniej, która to wartość, i zwracają wartość bool, aby w moim kodzie móc robić różne rzeczy w zależności od wyniku.Python: ustal, czy wszystkie elementy listy są tym samym obiektem.

Nie mogę wcześniej znać nazw właściwości, dlatego staram się stworzyć coś tak ogólnego, jak to tylko możliwe.

Aby przykład jasne, idealna funkcja o nazwie „all_same” będzie działać tak:

>>> property_list = ["one", "one", "one"] 
>>> all_same(property_list) 
True 
>>> property_list = ["one", "one", "two"] 
>>> all_same(property_list) 
False 

Myślałam dokonywania listę unikalnych elementów, a następnie sprawdzić, czy jej długość wynosi 1, ale Nie jestem pewien, czy jest to najbardziej eleganckie rozwiązanie.

+0

Wystarczy sobie sprawę, że samo pytanie tutaj: http://stackoverflow.com/questions/3844801/check-if-all-elements-in-a-list-are-identical. Jak połączyć te dwa pytania? – max

+0

Heh, pierwsze pytanie Widziałem, gdzie wcześniejsze pytanie jest duplikatem. Czas czasami działa odwrotnie. – wheaties

Odpowiedz

102
def all_same(items): 
    return all(x == items[0] for x in items) 

Przykład:

>>> def all_same(items): 
...  return all(x == items[0] for x in items) 
... 
>>> property_list = ["one", "one", "one"] 
>>> all_same(property_list) 
True 
>>> property_list = ["one", "one", "two"] 
>>> all_same(property_list) 
False 
>>> all_same([]) 
True 
+0

Bardzo miło, użyję tego, dzięki! – Einar

+22

'len (zestaw (przedmioty)) == 1' jest szybsze. – JulienD

+1

@muraveill To zależałoby znacznie od danych wejściowych. – FogleBird

41

Można oszukiwać i wykorzystywać set:

def all_same(items): 
    return len(set(items)) == 1 #== len(items) 

lub można użyć:

def all_same(items): 
    return all(map(lambda x: x == items[0], items)) 

lub jeśli masz do czynienia ze związkiem iterable zamiast listy:

def all_same(iterable): 
    it_copy = tee(iterable, 1) 
    return len(set(it_copy)) == 1 
+0

Zestaw miałby tylko jedną pozycję, lista miałaby N. – FogleBird

+1

Można użyć wyrażeń generatora w drugim kodzie. 'wszystko (x == pozycji [0] dla x w pozycjach)'. – kennytm

+10

len (zestaw (przedmioty)) == 1 zdecydowanie najbardziej idiomatyczny. –

9

pierwotnie interpretować można testować tożsamości („ten sam element”), ale tak naprawdę testowania równości („sama wartość”). (. Jeśli były badania tożsamości, należy jest zamiast ==)

def all_same(items): 
    it = iter(items) 
    for first in it: 
    break 
    else: 
    return True # empty case, note all([]) == True 
    return all(x == first for x in it) 

Powyższe działa na każdym iterable, nie tylko można znaleźć, w przeciwnym razie można użyć:

def all_same(L): 
    return all(x == L[0] for x in L) 

(Ale, IMHO, równie dobrze można wykorzystać ogólną wersję, że działa perfekcyjnie na listach)

+0

+1 Muszę pamiętać ten przepis. – aaronasterling

+0

@katrielalex: Następnie musisz spróbować/oprócz StopIteration; w tym momencie jest to zachowanie równoważne i tej samej długości. –

+1

Preferuję 'try: first = next (it) except StopIteration: return True' - Myślę, że przepływ jest wyraźniejszy - ale ta sama różnica, naprawdę. – katrielalex

4

działa to zarówno w przypadku sekwencji i iterables.

def all_same(items): 
    it = iter(items) 
    first = next(it, None) 
    return all(x == first for x in it) 
+1

Ah, wyobrażałem sobie, że sprawdziłeś "first is None", zamiast pozwalać na to. Daje to właściwy rezultat, ale wolę traktować to jako błąd/"wyjątkową okoliczność" zamiast polegać na późniejszym kodzie, aby w milczeniu zrobić właściwą rzecz. –

+0

Wiem, że jestem bardzo unpythonic w tej opinii, ale nie podoba mi się, że ładna pojedyncza linia zamienia się w cztery, ponieważ muszę złapać wyjątek (mówię ogólnie, użyłeś odpowiedzi "for/break in you"). Tak, wiem o EAFP, ale nadal, jeśli mogę tego uniknąć ... Dzięki za +1, jednak :-) – tokland

0

Prawdopodobnie będzie to szybsze, jeśli wiesz, że wartości znajdują się na liście.

def all_same(values): 
    return values.count(values[0]) == len(values) 
5

Najlepszym sposobem, aby to zrobić jest użycie Python sets.You trzeba zdefiniować all_same takiego:

def all_same(items): 
    return len(set(items)) == 1 

Test:

>>> def all_same(items): 
...  return len(set(items)) == 1 
... 
>>> 
>>> property_list = ["one", "one", "one"] 
>>> all_same(property_list) 
True 
>>> property_list = ["one", "one", "two"] 
>>> all_same(property_list) 
False 
>>> 
-1

Stworzyłem ten fragment kodu w tej samej sprawie po przemyśleniu tego. Nie jestem do końca pewien, czy to działa w każdym scenariuszu.

def all_same(list): 
    list[0]*len(list) == list 
+0

Obawiam się, że to w ogóle nie działa. Na przykład.'test_list = [1, 1]' i 'all_same (test_list)' zwraca 'False', ponieważ' test_list [0] = 1' i 'len (test_list) = 2', więc wyniki są po prostu' 1 * 2 = 2' . Następnie testujemy '2 == test_list', która nie jest True. –

Powiązane problemy