リスト内のすべての要素が同一かどうかを確認します


389

次の機能が必要です。

入力:alist

出力

  • True 入力リストのすべての要素が標準の等価演算子を使用して互いに等しいと評価された場合。
  • False さもないと。

パフォーマンス:もちろん、不要なオーバーヘッドが発生しないようにします。

私はそれが最善だと思います:

  • リストを反復する
  • 隣接する要素を比較する
  • ANDすべての結果のブール値

しかし、それを行うための最もPythonicな方法が何かはわかりません。


ショートサーキット機能の欠如は、早い段階で等しくない要素を持つ長い入力(約50要素以上)でのみ害を及ぼします。これが頻繁に発生する場合(どのくらいの頻度がリストの長さに依存するか)、短絡が必要です。最良の短絡アルゴリズムは@KennyTMのようですcheckEqual1。ただし、これにはかなりの費用がかかります。

  • パフォーマンスがほぼ同じリストで最大20倍
  • ショートリストのパフォーマンスは最大2.5倍

初期の不均等な要素を持つ長い入力が発生しない場合(または十分にまれにしか発生しない場合)、短絡は必要ありません。次に、最も速いのは@Ivo van der Wijkソリューションです。


3
と等しいa == bか、またはと同じa is bですか?
kennytm

1
ソリューションは空のリストを処理する必要がありますか?もしそうなら、何を返すべきですか?
Doug

1
a == bと同じです。空のリストを処理し、Trueを返します。
最大

2
他の推奨事項よりも遅いことはわかっfunctools.reduce(operator.eq, a)ていますが、提案されていないことに驚いています。
user2846495

回答:


420

一般的な方法:

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

一発ギャグ:

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

また、ワンライナー:

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

3つのバージョンの違いは次のとおりです。

  1. ではcheckEqual2、コンテンツハッシュ可能でなければなりません。
  2. checkEqual1また、checkEqual2任意のイテレータを使用できますがcheckEqual3、通常はリストやタプルなどの具体的なコンテナであるシーケンス入力を受け取る必要があります。
  3. checkEqual1 違いが見つかるとすぐに停止します。
  4. checkEqual1はより多くのPythonコードが含まれているため、最初に多くの項目が等しい場合は効率が低下します。
  5. 以来checkEqual2checkEqual3常にO(N)のコピー操作を実行し、あなたの入力のほとんどはFalseを返しますならば、彼らは時間がかかります。
  6. checkEqual2checkEqual3それがより比較に適応するのは難しいですa == bへをa is b

timeit 結果、Python 2.7および(s1、s4、s7、s9のみがTrueを返す必要があります)

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 = []

我々が得る

      | 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   |

注意:

# 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

1
ありがとう、これは選択肢の本当に役立つ説明です。パフォーマンステーブルを再確認してください。すべてミリ秒単位で、数値は正しいセルにありますか?
最大

7
@max:はい。1ミリ秒= 1000 usecであることに注意してください。
kennytm

1
非常に大規模な配列のメモリ使用量の分析、obj.__eq__whenの呼び出しを最適化するネイティブソリューションlhs is rhs、およびソート順リストの短絡をより迅速に行えるようにする順序外の最適化を忘れないでください。
Glenn Maynard

3
Ivo van der Wijkは、メモリ内のセットおよびO(1)よりも約5倍高速なシーケンスのための優れたソリューションを備えています。
aaronasterling

2
itertools回答として追加したレシピもあります。それをあなたのタイミングマトリックスに投入する価値があるかもしれません:-)。
mgilson 2016年

298

シーケンス(反復可能ではない)で機能するset()を使用するよりも速い解決策は、最初の要素を数えることです。これは、リストが空ではないことを前提としています(ただし、チェックして、空のリストで結果をどうするかを自分で決めるのは簡単です)

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

いくつかの簡単なベンチマーク:

>>> 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

5
OMG、これはセットソリューションより6倍高速です。(私のラップトップでは2億8000万要素/秒vs 4500万要素/秒)。なぜ???そして、それが短絡するようにそれを変更する方法はありますか(私はそうは思いません...)
最大

2
list.countには高度に最適化されたC実装があり、リストの長さは内部に格納されるため、len()も安価です。count()を短絡させる方法はありません。正確なカウントを取得するには、すべての要素を実際にチェックする必要があるためです。
Ivo van der Wijk

これを次のx.count(next(x)) == len(x)ように変更できますか?これにより、任意のコンテナxで機能しますか?Ahh .. nm、.countはシーケンスでのみ使用できることを確認しました。他の組み込みコンテナーに実装されないのはなぜですか?辞書内でカウントすることは、リスト内よりも本質的に意味がありませんか?
最大

4
イテレータには長さがない場合があります。たとえば、無限にすることも、動的に生成することもできます。イテレータの利点のほとんどを取り除いたリストに変換することによってのみ、その長さを見つけることができます
Ivo van der Wijk

申し訳ありませんが、私が意味したのはcount、反復子にが実装されていない理由lenであり、反復子に使用できない理由ではありません。答えはおそらくそれが単なる見落としであるということです。しかし.count()、シーケンスのデフォルトが非常に遅いため(純粋なpython)、それは私たちにとって無関係です。ソリューションが非常に高速である理由は、countによって提供されるC実装に依存しているためですlist。したがってcount、Cでメソッドを実装するためにイテラブルが発生したとしても、あなたのアプローチの恩恵を受けると思います。
最大

164

最も単純で最もエレガントな方法は次のとおりです。

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

(はい、これは空のリストでも機能します!これは、Pythonが遅延セマンティクスを使用する数少ないケースの1つであるためです。)

パフォーマンスに関しては、これはできるだけ早い時期に失敗するため、漸近的に最適です。


これは機能しますが、@ KennyTMよりも少し(1.5倍)遅くなりますcheckEqual1。理由はわかりません。
最大

4
max:おそらく、私が最適化を実行する手間をかけなかった可能性がありますfirst=myList[0] all(x==first for x in myList)。おそらく
ninjagecko

myList [0]は反復ごとに評価されると思います。>>> timeit.timeit( 'all([y == x [0] for y in x])'、 'x = [1] * 4000'、number = 10000)2.707076672740641 >>> timeit.timeit( 'x0 = x [0]; all([y == x0 for y in x]))、 'x = [1] * 4000'、number = 10000)2.0908854261426484
Matt Liberty

1
もちろん、最適化first=myList[0]によってIndexError空のリストがスローされることを明確にする必要があります。そのため、前述の最適化について話していたコメンターは、空のリストのエッジケースに対処する必要があります。ただし、オリジナルは問題ありません(リストが空の場合は評価されないため、x==myList[0]内では問題allありません)。
ninjagecko 2016年

1
これは明らかに正しい方法です。すべてのケースでスピードが必要な場合は、numpyなどを使用してください。
Henry Gomersall 2016年

45

セット比較作業:

len(set(the_list)) == 1

を使用setすると、すべての重複要素が削除されます。


26

リストをセットに変換できます。セットは重複できません。したがって、元のリストのすべての要素が同一である場合、セットには要素が1つだけ含まれます。

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

これはいいですが、短絡しないので、結果のリストの長さを計算する必要があります。
aaronasterling

15
なぜlen(set(input_list)) == 1ですか?
Nick Dandoulakis、

2
@codaddict。つまり、最初の2つの要素が異なっていても、検索全体が完了します。また、O(k)の余分なスペースを使用します。kはリスト内の個別の要素の数です。
aaronasterling

1
@最大。セットの構築はCで行われ、実装が悪いためです。少なくともジェネレータ式で行う必要があります。セットを使用せずに正しく実行する方法については、KennyTMの回答を参照してください。
aaronasterling

1
sets.Setは、「バージョン2.6で非推奨:組み込みのset / frozenset型がこのモジュールを置き換えます。」(docs.python.org/2/library/sets.htmlから)
Moberg

21

価値のあることとして、これは最近python-ideasメーリングリストに登場しました。これを実行するためのitertoolsレシピがすでにあることがわかります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)

おそらくそれは非常にうまく機能し、いくつかの素晴らしいプロパティを持っています。

  1. ショートサーキット:最初の等しくないアイテムが見つかるとすぐに、反復可能オブジェクトからのアイテムの消費を停止します。
  2. アイテムをハッシュ可能にする必要はありません。
  3. それは怠惰であり、チェックを行うためにO(1)の追加メモリのみを必要とします。

1言い換えれば、私はソリューションを思いついたとしてもそれを見つけたとしても信用できません。


3
最悪のシナリオでここにリストされている最も速い回答よりもはるかに高速です。
ChaimG

return next(g, f := next(g, g)) == f(もちろんpy3.8から)
Chris_Rands

17

これを行う2つの簡単な方法を次に示します

set()の使用

リストをセットに変換すると、重複する要素が削除されます。したがって、変換されたセットの長さが1の場合、すべての要素が同じであることを意味します。

len(set(input_list))==1

ここに例があります

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

all()の使用

これは、入力リストの最初の要素をリスト内の他のすべての要素と(同等)比較します。すべて同等の場合はTrueが返され、それ以外の場合はFalseが返されます。

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

ここに例があります

>>> 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

PSリスト全体が特定の値と等しいかどうかを確認する場合は、input_list [0]の値をsuibstitueできます。


1
ランタイムに関心のある人にとってlen(set(a))、10,000,000要素のリストでの実行には0.09秒allかかりましたが、実行には0.9秒(10倍以上)かかりました。
Elliptica

2
@Ellipticaによって言及されたパフォーマンススコアに加えて、Pythonの単純さのためにこの回答も気に入っています
NickBraunagel

11

これは別のオプションで、len(set(x))==1長いリストよりも高速です(短絡を使用)

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

短絡を無視すると、私のコンピューターの設定ソリューションより3倍遅くなります。したがって、不均等な要素がリストの最初の3分の1に平均して見つかれば、平均して速くなります。
最大

9

これは簡単な方法です:

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

これは少し複雑で、関数呼び出しのオーバーヘッドが発生しますが、セマンティクスはより明確に綴られています。

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

を使用すると、ここで冗長な比較を回避できfor elem in mylist[1:]ます。elem[0] is elem[0]おそらく、インタープリターがおそらくその比較を非常に迅速に行うことができると思うので、速度は大幅に向上します。
ブレンダン2017年

5

すべての要素が最初のものと等しいかどうかを確認します。

np.allclose(array, array[0])


サードパーティのモジュールが必要です。
1919

4

これは「最もPythonic」であるに違いありませんが、次のようなものです。

>>> 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

トリックを行います。


1
あなたのforループは、よりPython的にさせることができるif any(item != list[0] for item in list[1:]): return False正確に同じ意味で、。
musiphil

4

あなたがもう少し読みやすい何かに興味があるなら(もちろん、それほど効率的ではありません)、あなたは試すことができます:

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

私は実際には、1つのリストのすべての要素が同一であるかどうかを確認しようとしています。2つの別個のリストが同一の場合はそうではありません。
最大

4

リストをセットに変換し、セット内の要素の数を見つけます。結果が1の場合、要素は同一であり、そうでない場合、リスト内の要素は同一ではありません。

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

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

4

使用に関してreduce()lambda。これが私が個人的に他のいくつかの答えよりも優れていると思う作業コードです。

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

すべてのアイテムが同じかどうかに応じて、最初の値がブール値であるタプルを返します。


記述されているように(試行[1, 2, 2])、コードに小さな誤りがあります。前のブール値は考慮されません。これは交換することによって固定することが可能x[1] == yx[0] and x[1] == y
撮影

3

私はします:

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

条件anyが見つかるとすぐに反復可能オブジェクトの検索を停止しTrueます。


引数が1つだけの場合は、ジェネレータ式を括弧で囲む必要はありません。
ninjagecko 2012

そうall()、なぜ使用しないのall(x == seq[0] for x in seq)ですか?よりパイソンのように見え、同じように実行する必要があります
チェンA.

2
>>> 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
def allTheSame(i):
    j = itertools.groupby(i)
    for k in j: break
    for k in j: return False
    return True

「すべて」を持たないPython 2.4で動作します。


1
for k in j: breakと同等next(j)です。def allTheSame(x): return len(list(itertools.groupby(x))<2)効率を気にしないのなら、あなたもそうすることができたでしょう。
ninjagecko 2012

2

マップとラムダを使用できます

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

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

2

またはdiffnumpyのメソッドを使用します:

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

そして呼び出すには:

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

出力:

True

not np.any(np.diff(l))もう少し速いと思います。
GZ0

2

またはnumpyのdiffメソッドを使用します:

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

そして呼び出すには:

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

出力:

本当


この回答は、昨年のU9-Forwardの回答と同じです。
mhwombat

いい目!同じ構造/ APIを使用しましたが、私のメソッドはnp.uniqueとshapeを使用します。U9の関数はnp.all()とnp.diff()を使用します-これらの関数のどちらも使用しません。
Luis B

1

できるよ:

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

pythonにのような演算子をインポートさせるのはかなり面倒ですoperator.and_。python3以降、もインポートする必要がありますfunctools.reduce

(このメソッドは、等しくない値が見つかっても壊れないため、使用しないでください。ただし、リスト全体の調査を続行します。完全を期すための回答としてここに記載しています。)


これは短絡しません。なぜ他のソリューションよりもそれを好むのですか?
最大

@max:その理由から、そうはしません。完全を期すために含めました。私はおそらくそれを言及するためにそれを編集するべきです、ありがとう。
ninjagecko 2012

1
lambda lst: reduce(lambda a,b:(b,b==a[0] and a[1]), lst, (lst[0], True))[1]

次のものは短絡します:

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

あなたの最初のコードは明らかに間違っていました:reduce(lambda a,b:a==b, [2,2,2])収量False...私はそれを編集しましたが、この方法ではもうきれいではありません
berdario

@berdarioでは、誰かが書いた内容を変更するのではなく、自分で答えを書いておくべきです。この回答が間違っていたと思われる場合は、コメントしたり、反対票を投じたりできます。
Gorpik

3
何かを修正する方がましですが、すべての人に読んでもらうために残しておくよりも、その理由を説明するコメントが欠落している可能性があります
berdario

3
「いつ投稿を編集するべきですか?」「投稿をより良くできると感じたときはいつでもそうする傾向があります。編集をお勧めします!」
berdario 2014年

1

リストをセットに変更します。次に、セットのサイズが1のみの場合、それらは同じでなければなりません。

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

1

純粋なPython再帰オプションもあります。

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

ただし、何らかの理由で、他のオプションよりも2桁遅い場合があります。C言語の考え方から来たので、これはもっと速いと思っていましたが、そうではありません!

他の欠点は、この場合に調整する必要があるPythonの再帰制限があることです。たとえば、これを使用ます。


0

を使用.nunique()して、リスト内の一意のアイテムの数を見つけることができます。

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

使用できますset。セットを作成し、反復的な要素を削除します。次に、要素が1つ以下であることを確認します。

if len(set(your_list)) <= 1:
    print('all ements are equal')

例:

>>> len(set([5, 5])) <= 1
True
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.