it-swarm.com.de

Überprüfen Sie, ob alle Elemente in einer Liste identisch sind

Ich brauche folgende Funktion:

Eingabe: a list

Ausgabe:

  • True wenn alle Elemente in der Eingabeliste mit dem Standard-Gleichheitsoperator als gleich ausgewertet werden;
  • False ansonsten.

Performance: Natürlich ziehe ich es vor, keinen unnötigen Overhead zu verursachen.

Ich denke, es wäre am besten:

  • durchlaufen Sie die Liste
  • vergleiche benachbarte Elemente
  • und AND alle resultierenden Booleschen Werte

Aber ich bin mir nicht sicher, wie ich das am besten mit Pythonic machen kann.


EDIT :

Vielen Dank für die tollen Antworten. Ich habe mehrere Bewertungen erhalten, und es war wirklich schwierig, zwischen @KennyTM- und @Ivo van der Wijk-Lösungen zu wählen.

Das Fehlen einer Kurzschlussfunktion schadet nur einem langen Eingang (über 50 Elemente), der zu Beginn ungleiche Elemente aufweist. Wenn dies oft genug vorkommt (wie oft es von der Länge der Listen abhängt), ist der Kurzschluss erforderlich. Der beste Kurzschlussalgorithmus scheint @KennyTM checkEqual1 Zu sein. Es zahlt sich jedoch ein erheblicher Aufwand dafür aus:

  • bis zu 20-fache Leistung bei nahezu identischen Listen
  • bis zu 2,5-fache Leistung auf Kurzlisten

Wenn die langen Eingaben mit frühen ungleichen Elementen nicht (oder nur sehr selten) auftreten, ist kein Kurzschluss erforderlich. Dann ist @Ivo van der Wijk die mit Abstand schnellste Lösung.

339
max

Allgemeine Methode:

def checkEqual1(iterator):
    iterator = iter(iterator)
    try:
        first = next(iterator)
    except StopIteration:
        return True
    return all(first == rest for rest in iterator)

Einzeiler:

def checkEqual2(iterator):
   return len(set(iterator)) <= 1

Auch Einzeiler:

def checkEqual3(lst):
   return lst[1:] == lst[:-1]

Der Unterschied zwischen den 3 Versionen besteht darin, dass:

  1. Im checkEqual2 Der Inhalt muss hashbar sein.
  2. checkEqual1 und checkEqual2 kann beliebige Iteratoren verwenden, aber checkEqual3 muss eine Sequenzeingabe übernehmen, normalerweise konkrete Container wie eine Liste oder ein Tupel.
  3. checkEqual1 stoppt, sobald ein Unterschied festgestellt wird.
  4. Schon seit checkEqual1 enthält mehr Python Code, es ist weniger effizient, wenn viele der Elemente am Anfang gleich sind.
  5. Schon seit checkEqual2 und checkEqual3 Führe immer O(N) Kopiervorgänge aus. Sie dauern länger, wenn der Großteil deiner Eingaben Falsch zurückgibt.
  6. Zum checkEqual2 und checkEqual3 es ist schwieriger, den Vergleich von a == b bis a is b.

timeit result, for Python 2.7 und (nur s1, s4, s7, s9 sollten True zurückgeben)

s1 = [1] * 5000
s2 = [1] * 4999 + [2]
s3 = [2] + [1]*4999
s4 = [set([9])] * 5000
s5 = [set([9])] * 4999 + [set([10])]
s6 = [set([10])] + [set([9])] * 4999
s7 = [1,1]
s8 = [1,2]
s9 = []

wir bekommen

      | checkEqual1 | checkEqual2 | checkEqual3  | checkEqualIvo | checkEqual6502 |
|-----|-------------|-------------|--------------|---------------|----------------|
| s1  | 1.19   msec | 348    usec | 183     usec | 51.6    usec  | 121     usec   |
| s2  | 1.17   msec | 376    usec | 185     usec | 50.9    usec  | 118     usec   |
| s3  | 4.17   usec | 348    usec | 120     usec | 264     usec  | 61.3    usec   |
|     |             |             |              |               |                |
| s4  | 1.73   msec |             | 182     usec | 50.5    usec  | 121     usec   |
| s5  | 1.71   msec |             | 181     usec | 50.6    usec  | 125     usec   |
| s6  | 4.29   usec |             | 122     usec | 423     usec  | 61.1    usec   |
|     |             |             |              |               |                |
| s7  | 3.1    usec | 1.4    usec | 1.24    usec | 0.932   usec  | 1.92    usec   |
| s8  | 4.07   usec | 1.54   usec | 1.28    usec | 0.997   usec  | 1.79    usec   |
| s9  | 5.91   usec | 1.25   usec | 0.749   usec | 0.407   usec  | 0.386   usec   |

Hinweis:

# http://stackoverflow.com/q/3844948/
def checkEqualIvo(lst):
    return not lst or lst.count(lst[0]) == len(lst)

# http://stackoverflow.com/q/3844931/
def checkEqual6502(lst):
    return not lst or [lst[0]]*len(lst) == lst
367
kennytm

Eine Lösung, die schneller als die Verwendung von set () für Sequenzen (nicht für iterable) ist, besteht darin, einfach das erste Element zu zählen. Dies setzt voraus, dass die Liste nicht leer ist (es ist jedoch trivial, dies zu überprüfen und selbst zu entscheiden, wie das Ergebnis auf einer leeren Liste aussehen soll).

x.count(x[0]) == len(x)

einige einfache Benchmarks:

>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*5000', number=10000)
1.4383411407470703
>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*4999+[2]', number=10000)
1.4765670299530029
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*5000', number=10000)
0.26274609565734863
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*4999+[2]', number=10000)
0.25654196739196777
264

Der einfachste und eleganteste Weg ist wie folgt:

all(x==myList[0] for x in myList)

(Ja, das funktioniert sogar mit der leeren Liste! Dies ist, weil dies einer der wenigen Fälle ist, in denen python faul semantisch ist.)

In Bezug auf die Leistung schlägt dies zum frühestmöglichen Zeitpunkt fehl, sodass es asymptotisch optimal ist.

129
ninjagecko

Eine gesetzte Vergleichsarbeit:

len(set(the_list)) == 1

Mit set werden alle doppelten Elemente entfernt.

40
cbalawat

Sie können die Liste in ein Set konvertieren. Ein Satz darf keine Duplikate enthalten. Wenn also alle Elemente in der ursprünglichen Liste identisch sind, enthält die Menge nur ein Element.

if len(sets.Set(input_list)) == 1
// input_list has all identical elements.
24
codaddict

Für das, was es wert ist, tauchte dies kürzlich auf der Python-Ideen-Mailingliste auf. Es stellt sich heraus, dass es dafür bereits ein itertools-Rezept gibt:1

def all_equal(iterable):
    "Returns True if all the elements are equal to each other"
    g = groupby(iterable)
    return next(g, True) and not next(g, False)

Angeblich funktioniert es sehr gut und hat ein paar nette Eigenschaften.

  1. Kurzschlüsse: Sobald der erste ungleiche Gegenstand gefunden wird, werden keine Gegenstände mehr aus der Iterationsdatei verbraucht.
  2. Es ist nicht erforderlich, dass Gegenstände hashbar sind.
  3. Es ist faul und benötigt nur O(1) zusätzlichen Speicher, um die Prüfung durchzuführen.

1Mit anderen Worten, ich kann nicht die Ehre dafür in Anspruch nehmen, eine Lösung gefunden zu haben, und ich kann auch nicht die Ehre dafür in Anspruch nehmen, sie überhaupt gefunden zu haben .

15
mgilson

Hier sind zwei einfache Möglichkeiten, dies zu tun

using set ()

Beim Konvertieren der Liste in eine Gruppe werden doppelte Elemente entfernt. Wenn also die Länge der konvertierten Menge 1 ist, bedeutet dies, dass alle Elemente gleich sind.

len(set(input_list))==1

Hier ist ein Beispiel

>>> a = ['not', 'the', 'same']
>>> b = ['same', 'same', 'same']
>>> len(set(a))==1  # == 3
False
>>> len(set(b))==1  # == 1
True

mit all ()

Dies vergleicht (äquivalent) das erste Element der Eingabeliste mit jedem anderen Element in der Liste. Wenn alle äquivalent sind, wird True zurückgegeben, andernfalls wird False zurückgegeben.

all(element==input_list[0] for element in input_list)

Hier ist ein Beispiel

>>> a = [1, 2, 3, 4, 5]
>>> b = [1, 1, 1, 1, 1]
>>> all(number==a[0] for number in a)
False
>>> all(number==b[0] for number in b)
True

P.S Wenn Sie prüfen, ob die gesamte Liste einem bestimmten Wert entspricht, können Sie den Wert für input_list [0] eingeben.

15

Dies ist eine weitere Option, schneller als len(set(x))==1 für lange Listen (verwendet Kurzschluss)

def constantList(x):
    return x and [x[0]]*len(x) == x
10
6502

Dies ist eine einfache Methode:

result = mylist and all(mylist[0] == elem for elem in mylist)

Dies ist etwas komplizierter, es verursacht einen Funktionsaufruf-Overhead, aber die Semantik ist klarer formuliert:

def all_identical(seq):
    if not seq:
        # empty list is False.
        return False
    first = seq[0]
    return all(first == elem for elem in seq)
8
Jerub

Wenn Sie sich für etwas Lesbareres interessieren (aber natürlich nicht so effizient sind), können Sie versuchen:

def compare_lists(list1, list2):
    if len(list1) != len(list2): # Weed out unequal length lists.
        return False
    for item in list1:
        if item not in list2:
            return False
    return True

a_list_1 = ['Apple', 'orange', 'grape', 'pear']
a_list_2 = ['pear', 'orange', 'grape', 'Apple']

b_list_1 = ['Apple', 'orange', 'grape', 'pear']
b_list_2 = ['Apple', 'orange', 'banana', 'pear']

c_list_1 = ['Apple', 'orange', 'grape']
c_list_2 = ['grape', 'orange']

print compare_lists(a_list_1, a_list_2) # Returns True
print compare_lists(b_list_1, b_list_2) # Returns False
print compare_lists(c_list_1, c_list_2) # Returns False
4
Joshua Burns

Zweifel, das ist die "pythonischste", aber so etwas wie:

>>> falseList = [1,2,3,4]
>>> trueList = [1, 1, 1]
>>> 
>>> def testList(list):
...   for item in list[1:]:
...     if item != list[0]:
...       return False
...   return True
... 
>>> testList(falseList)
False
>>> testList(trueList)
True

würde den Trick machen.

4
machineghost

Überprüfen Sie, ob alle Elemente gleich dem ersten sind.

np.allclose(array, array[0])

4
Gusev Slava

Konvertieren Sie die Liste in die Menge und ermitteln Sie die Anzahl der Elemente in der Menge. Wenn das Ergebnis 1 ist, enthält es identische Elemente. Wenn nicht, sind die Elemente in der Liste nicht identisch.

list1 = [1,1,1]
len(set(list1)) 
>1

list1 = [1,2,3]
len(set(list1)
>3
3
DePP

Bezüglich der Verwendung von reduce() mit lambda. Hier ist ein Arbeitscode, den ich persönlich viel netter finde als einige der anderen Antworten.

reduce(lambda x, y: (x[1]==y, y), [2, 2, 2], (True, 2))

Gibt ein Trupel zurück, bei dem der erste Wert der Boolesche Wert ist, wenn alle Elemente identisch sind oder nicht.

3
Marcus Lind

Ja, würde ich:

not any((x[i] != x[i+1] for i in range(0, len(x)-1)))

as any bricht die Suche in der Iteration ab, sobald eine True Bedingung gefunden wird.

3
Robert Rossney

Oder benutze diff Methode von numpy:

import numpy as np
def allthesame(l):
    return np.unique(l).shape[0]<=1

Und um anzurufen:

print(allthesame([1,1,1]))

Ausgabe:

Wahr

2
Luis B

Kann Karte und Lambda verwenden

lst = [1,1,1,1,1,1,1,1,1]

print all(map(lambda x: x == lst[0], lst[1:]))
2
SuperNova

Oder benutze die diff Methode:

import numpy as np
def allthesame(l):
    return np.all(np.diff(l)==0)

Und um anzurufen:

print(allthesame([1,1,1]))

Ausgabe:

True
2
U10-Forward
def allTheSame(i):
    j = itertools.groupby(i)
    for k in j: break
    for k in j: return False
    return True

Funktioniert in Python 2.4, das nicht "all" hat.

2
itertool
>>> a = [1, 2, 3, 4, 5, 6]
>>> z = [(a[x], a[x+1]) for x in range(0, len(a)-1)]
>>> z
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
# Replacing it with the test
>>> z = [(a[x] == a[x+1]) for x in range(0, len(a)-1)]
>>> z
[False, False, False, False, False]
>>> if False in z : Print "All elements are not equal"
2
pyfunc
lambda lst: reduce(lambda a,b:(b,b==a[0] and a[1]), lst, (lst[0], True))[1]

Der nächste wird einen Kurzschluss verursachen:

all(itertools.imap(lambda i:yourlist[i]==yourlist[i+1], xrange(len(yourlist)-1)))
1
user3015260

Es gibt auch eine reine Python rekursive Option:

 def checkEqual(lst):
    if len(lst)==2 :
        return lst[0]==lst[1]
    else:
        return lst[0]==lst[1] and checkEqual(lst[1:])

Aus irgendeinem Grund ist es jedoch in einigen Fällen um zwei Größenordnungen langsamer als bei anderen Optionen. Aus der Mentalität der C-Sprache kommend hatte ich erwartet, dass dies schneller sein würde, aber das ist es nicht!

Der andere Nachteil ist, dass es in Python) ein Rekursionslimit gibt, das in diesem Fall angepasst werden muss. Zum Beispiel mit this .

1
Foad

Ändern Sie die Liste in einen Satz. Wenn die Größe des Sets dann nur 1 ist, müssen sie gleich gewesen sein.

if len(set(my_list)) == 1:
1
Lumo5

Du kannst tun:

reduce(and_, (x==yourList[0] for x in yourList), True)

Es ist ziemlich ärgerlich, dass Sie mit python= die Operatoren wie operator.and_ Importieren. Ab python3 müssen Sie auch functools.reduce Importieren.

(Sie sollten diese Methode nicht verwenden, da sie nicht abbricht, wenn sie ungleiche Werte findet, sondern die gesamte Liste weiter untersucht. Sie wird hier nur als Antwort auf die Vollständigkeit angegeben.)

1
ninjagecko

Sie können .nunique() verwenden, um die Anzahl der eindeutigen Elemente in einer Liste zu ermitteln.

def identical_elements(list):
    series = pd.Series(list)
    if series.nunique() == 1: identical = True
    else:  identical = False
    return identical



identical_elements(['a', 'a'])
Out[427]: True

identical_elements(['a', 'b'])
Out[428]: False
0
Saeed