web-dev-qa-db-ja.com

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

以下の機能が必要です。

入力:a list

出力

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

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

私はそれが最善であると思う:

  • リストを繰り返す
  • 隣接する要素を比較する
  • 結果のすべてのブール値とAND

しかし、私はそれを行うための最もPythonicの方法が何であるかわからない.


EDIT

素晴らしい回答をありがとうございました。いくつか評価したところ、@ KennyTMと@Ivo van der Wijkのソリューションを選択するのは非常に困難でした。

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

  • 最大20倍の性能のほぼ同一のリスト
  • ショートリストで最大2.5倍のパフォーマンス

初期の不等要素を含む長い入力が発生しない(またはほとんど発生しない)場合は、短絡は不要です。それから、はるかに最速は@ Ivo van der Wijkソリューションです。

325
max

一般的な方法:

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. checkEqual1checkEqual2は任意のイテレータを使うことができますが、checkEqual3はシーケンス入力、典型的にはリストやTupleのような具体的なコンテナーを取ります。
  3. 違いが見つかるとすぐにcheckEqual1は停止します。
  4. checkEqual1にはより多くのPythonコードが含まれているため、最初は多くの項目が等しい場合は効率が悪くなります。
  5. checkEqual2checkEqual3は常にO(N)コピー操作を実行するので、あなたの入力の大部分がFalseを返すならば、それらはより長くかかります。
  6. checkEqual2checkEqual3の場合、a == bからa is bへの比較を調整するのは難しいです。

Python 2.7以降の場合はtimeitの結果(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
352
kennytm

シーケンス(反復可能ではない)に対して機能する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
262

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

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

(はい、これはnullリストでも動作します!これはpythonが遅延セマンティクスを持つ数少ないケースの1つだからです。)

パフォーマンスに関しては、これは可能な限り早い時点で失敗するため、漸近的に最適です。

124
ninjagecko

セット比較作業

len(set(the_list)) == 1

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

38
cbalawat

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

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

それが価値があるもののために、これは最近 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)

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

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

1言い換えれば、私はその解決策を思いついたことに対して信用を取ることはできません - また、findingitについて信用することもできません。

15
mgilson

これをする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

P.Sリスト全体が特定の値と等しいかどうかを確認する場合は、for input_list [0]に値を代入することができます。

14

これは別のオプションです。長いリストではlen(set(x))==1より高速です(ショートサーキットを使用します)。

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

これは簡単な方法です。

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

もう少し読みやすいものに興味があるなら(もちろん効率的ではありません)、

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

これが「最もピトニック」であることを疑うが、しかしのようなもの:

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

トリックをするだろう。

4
machineghost

リストをセットに変換してから、セット内の要素数を見つけます。結果が1であれば、それは同一の要素を持ち、そうでなければ、リスト内の要素は同一ではありません。

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

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

reduce()lambdaと一緒に使用することについて。これは私が個人的に他のいくつかの答えよりもずっと良いと思う実用的なコードです。

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

すべての項目が同じであるかどうかにかかわらず、最初の値がブール値であるトリプルを返します。

3
Marcus Lind

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

np.allclose(array, array[0])

3
Gusev Slava

私はやる:

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

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

3
Robert Rossney

またはnumpyのdiffメソッドを使う:

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

そして呼び出すために:

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

出力:

本当

2
Luis B

地図とラムダが使える

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

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

あるいは、numpyのdiffメソッドを使用してください。

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

そして呼び出すために:

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

出力:

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

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

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]

次のものは短絡します:

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

純粋な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言語の考え方から来たので、これはもっと速いと思いましたが、そうではありません!

もう1つの欠点は、Pythonにはこの場合に調整が必要な再帰制限があることです。例えば this を使用します。

1
Foad

リストをセットに変更してください。その場合、セットのサイズが1だけであれば、それらは同じであったはずです。

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

できるよ:

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

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

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

1
ninjagecko

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