Potrzebuję następującej funkcji:
Dane wejściowe : alist
Wyjście :
True
jeżeli wszystkie elementy na liście danych wejściowych oceniają się jako równe za pomocą standardowego operatora równości;False
Inaczej.
Wydajność : oczywiście wolę nie ponosić niepotrzebnego obciążenia.
Myślę, że najlepiej byłoby:
- iteruj po liście
- porównaj sąsiednie elementy
- i
AND
wszystkie wynikowe wartości boolowskie
Ale nie jestem pewien, jaki jest najbardziej Pythoniczny sposób na zrobienie tego.
Brak funkcji zwarcia boli tylko na długim wejściu (ponad ~ 50 elementów), które mają nierówne elementy na początku. Jeśli zdarza się to wystarczająco często (jak często zależy od długości list), wymagane jest zwarcie. Najlepszym algorytmem zwarciowym wydaje się być @KennyTM checkEqual1
. Płacą jednak za to znaczne koszty:
- do 20x w wydajności prawie identyczne listy
- do 2,5x wydajności na krótkich listach
Jeśli długie sygnały wejściowe z wczesnymi nierównymi elementami nie występują (lub występują dość rzadko), zwarcie nie jest wymagane. Zdecydowanie najszybsze jest rozwiązanie @Ivo van der Wijk.
a == b
lub identyczna jak wa is b
?functools.reduce(operator.eq, a)
że nie został zasugerowany.Odpowiedzi:
Ogólna metoda:
Jednowarstwowy:
Również jednowarstwowy:
Różnica między 3 wersjami polega na tym, że:
checkEqual2
treści musi być hashable.checkEqual1
icheckEqual2
może używać dowolnych iteratorów, alecheckEqual3
musi pobierać dane wejściowe sekwencji, zwykle konkretne pojemniki, takie jak lista lub krotka.checkEqual1
zatrzymuje się, gdy tylko zostanie znaleziona różnica.checkEqual1
zawiera więcej kodu Python, jest mniej wydajny, gdy wiele elementów jest na początku równych.checkEqual2
icheckEqual3
zawsze wykonuj operacje kopiowania O (N), potrwają dłużej, jeśli większość danych wejściowych zwróci False.checkEqual2
icheckEqual3
trudniej jest dostosować porównanie oda == b
doa is b
.timeit
wynik, dla Python 2.7 i (tylko s1, s4, s7, s9 powinny zwracać wartość True)dostajemy
Uwaga:
źródło
obj.__eq__
czasemlhs is rhs
i optymalizacje poza kolejnością, aby umożliwić szybsze sortowanie zwartych list.itertools
przepis, który dodałem jako odpowiedź. Może warto wrzucić to do swojej macierzy czasu :-).Rozwiązaniem szybszym niż użycie set () działającego na sekwencjach (nie iterowalnych) jest po prostu policzenie pierwszego elementu. Zakłada się, że lista nie jest pusta (ale sprawdzenie tego jest trywialne i sam decydujesz, jaki wynik powinien znaleźć się na pustej liście)
kilka prostych testów:
źródło
x.count(next(x)) == len(x)
aby działał dla dowolnego kontenera x? Ahh .. nm, właśnie zobaczyłem, że .count jest dostępny tylko dla sekwencji. Dlaczego nie jest zaimplementowany dla innych wbudowanych kontenerów? Czy liczenie w słowniku jest z natury mniej znaczące niż w przypadku listy?count
nie jest zaimplementowanelen
dla iteratorów , a nie dlaczego nie jest dostępne dla iteratorów. Odpowiedź jest prawdopodobnie taka, że to tylko przeoczenie. Jest to jednak dla nas nieistotne, ponieważ domyślna.count()
sekwencja jest bardzo wolna (czysty python). Powodem, dla którego twoje rozwiązanie jest tak szybkie, jest to, że polega ono na C-implementacjicount
dostarczonej przezlist
. Tak więc przypuszczam, że cokolwiek by się powtórzyło zaimplementowaniecount
metody w C, skorzysta z twojego podejścia.Najprostszy i najbardziej elegancki sposób wygląda następująco:
(Tak, to działa nawet z pustą listą! To dlatego, że jest to jeden z niewielu przypadków, w których python ma leniwą semantykę.)
Jeśli chodzi o wydajność, to zawiedzie jak najwcześniej, więc jest asymptotycznie optymalna.
źródło
checkEqual1
. Nie jestem pewien dlaczego.first=myList[0]
all(x==first for x in myList)
, być możefirst=myList[0]
wyrzuci znakIndexError
na pustą listę, więc komentatorzy, którzy mówili o tej optymalizacji, o której wspomniałem, będą musieli poradzić sobie z sytuacją skrajną pustej listy. Jednak oryginał jest w porządku (x==myList[0]
jest w porządku,all
ponieważ nigdy nie jest oceniany, jeśli lista jest pusta).Zestaw pracy porównawczej:
Użycie
set
usuwa wszystkie zduplikowane elementy.źródło
Możesz przekonwertować listę na zestaw. Zestaw nie może mieć duplikatów. Jeśli więc wszystkie elementy na oryginalnej liście są identyczne, zestaw będzie miał tylko jeden element.
źródło
len(set(input_list)) == 1
?Co warte jest, pojawiło się to ostatnio na liście mailingowej python-ideas . Okazuje się, że istnieje już przepis na itertools : 1
Podobno działa bardzo ładnie i ma kilka fajnych właściwości.
1 Innymi słowy, nie mogę się pochwalić za wymyślenie rozwiązania - ani nie mogę się pochwalić za to, że go znalazłem .
źródło
return next(g, f := next(g, g)) == f
(z py3.8 oczywiście)Oto dwa proste sposoby na zrobienie tego
za pomocą set ()
Podczas konwertowania listy na zestaw usuwane są zduplikowane elementy. Jeśli więc długość przekonwertowanego zestawu wynosi 1, oznacza to, że wszystkie elementy są takie same.
Oto przykład
using all ()
Spowoduje to porównanie (równoważność) pierwszego elementu listy wejściowej z każdym innym elementem na liście. Jeśli wszystkie są równoważne, prawda zostanie zwrócona, w przeciwnym razie zwróci się fałsz.
Oto przykład
PS Jeśli sprawdzasz, czy cała lista jest odpowiednikiem określonej wartości, możesz sprawdzić wartość w parametrze lista_wejściowa [0].
źródło
len(set(a))
na liście 10 000 000 elementów zajęło 0,09 s, podczas gdy wykonanieall
zajęło 0,9 s (10 razy dłużej).To kolejna opcja, szybsza niż w
len(set(x))==1
przypadku długich list (wykorzystuje zwarcie)źródło
Jest to prosty sposób:
Jest to nieco bardziej skomplikowane, powoduje narzut wywołania funkcji, ale semantyka jest wyraźniej określona:
źródło
for elem in mylist[1:]
. Wątpię jednak, że znacznie poprawia prędkość, ponieważelem[0] is elem[0]
tak sądzę , że tłumacz może prawdopodobnie dokonać tego porównania bardzo szybko.Sprawdź, czy wszystkie elementy są równe pierwszemu.
np.allclose(array, array[0])
źródło
Wątpię, że jest to „najbardziej Python”, ale coś takiego:
załatwi sprawę.
źródło
for
pętla może zostać przekształcona w język Pythonaif any(item != list[0] for item in list[1:]): return False
, z dokładnie taką samą semantyką.Jeśli interesuje Cię coś nieco bardziej czytelnego (ale oczywiście nie tak wydajnego), możesz spróbować:
źródło
Przekształć listę w zestaw, a następnie znajdź liczbę elementów w zestawie. Jeśli wynikiem jest 1, ma identyczne elementy, a jeśli nie, to elementy na liście nie są identyczne.
źródło
Odnośnie używania
reduce()
zlambda
. Oto działający kod, który moim zdaniem jest o wiele ładniejszy niż niektóre inne odpowiedzi.Zwraca krotkę, w której pierwszą wartością jest wartość logiczna, jeśli wszystkie elementy są takie same lub nie.
źródło
[1, 2, 2]
): nie bierze on pod uwagę poprzedniej wartości logicznej. Można to naprawić poprzez wymianęx[1] == y
zx[0] and x[1] == y
.Mogłabym zrobić:
ponieważ
any
przestaje przeszukiwać iterowalny, gdy tylko znajdzieTrue
warunek.źródło
all()
, dlaczego nie użyćall(x == seq[0] for x in seq)
? wygląda bardziej pytonicznie i powinien działać tak samoźródło
Działa w Pythonie 2.4, który nie ma „wszystkiego”.
źródło
for k in j: break
jest równoważne znext(j)
. Mógłbyś to zrobićdef allTheSame(x): return len(list(itertools.groupby(x))<2)
, gdybyś nie dbał o wydajność.Może korzystać z mapy i lambda
źródło
Lub użyj
diff
metody numpy:I zadzwonić:
Wynik:
źródło
not np.any(np.diff(l))
może być trochę szybszy.Lub użyj metody różniczkowej numpy:
I zadzwonić:
Wynik:
Prawdziwe
źródło
Możesz to zrobić:
Dość denerwujące jest to, że Python zmusza do importowania operatorów takich jak
operator.and_
. Począwszy od python3, musisz także zaimportowaćfunctools.reduce
.(Nie powinieneś używać tej metody, ponieważ nie złamie się, jeśli znajdzie nierównomierne wartości, ale będzie nadal sprawdzać całą listę. Została ona tutaj uwzględniona jako odpowiedź na kompletność).
źródło
Następny spowoduje zwarcie:
źródło
reduce(lambda a,b:a==b, [2,2,2])
dajeFalse
... Zredagowałem go, ale w ten sposób już nie jest ładnyZmień listę na zestaw. Zatem jeśli rozmiar zestawu wynosi tylko 1, muszą być takie same.
źródło
Istnieje również czysta opcja rekurencyjna w języku Python:
Jednak z jakiegoś powodu w niektórych przypadkach jest on o dwa rzędy wielkości wolniejszy niż w przypadku innych opcji. Pochodząc z mentalności języka C spodziewałem się, że będzie to szybsze, ale tak nie jest!
Inną wadą jest to, że w Pythonie istnieje limit rekurencji, który w tym przypadku należy dostosować. Na przykład używając tego .
źródło
Możesz użyć,
.nunique()
aby znaleźć liczbę unikalnych przedmiotów na liście.źródło
możesz użyć
set
. Stworzy zestaw i usunie powtarzające się elementy. Następnie sprawdź, czy nie ma więcej niż 1 element.Przykład:
źródło