以下の機能が必要です。
入力:a list
出力:
True
。False
。パフォーマンス:もちろん、不要なオーバーヘッドを招かないようにします。
私はそれが最善であると思う:
AND
しかし、私はそれを行うための最もPythonicの方法が何であるかわからない.
EDIT:
素晴らしい回答をありがとうございました。いくつか評価したところ、@ KennyTMと@Ivo van der Wijkのソリューションを選択するのは非常に困難でした。
短絡機能の欠如は、早い段階で等しくない要素を持つ長い入力(〜50要素以上)を傷つけるだけです。これが十分に頻繁に発生する場合(リストの長さによってどれくらいの頻度で決まるか)、短絡が必要です。最善のショートサーキットアルゴリズムは@KennyTM checkEqual1
のようです。しかし、これにはかなりの費用がかかります。
初期の不等要素を含む長い入力が発生しない(またはほとんど発生しない)場合は、短絡は不要です。それから、はるかに最速は@ Ivo van der Wijkソリューションです。
一般的な方法:
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つのバージョンの違いは、次のとおりです。
checkEqual2
では、コンテンツはハッシュ可能でなければなりません。checkEqual1
とcheckEqual2
は任意のイテレータを使うことができますが、checkEqual3
はシーケンス入力、典型的にはリストやTupleのような具体的なコンテナーを取ります。checkEqual1
は停止します。checkEqual1
にはより多くのPythonコードが含まれているため、最初は多くの項目が等しい場合は効率が悪くなります。checkEqual2
とcheckEqual3
は常にO(N)コピー操作を実行するので、あなたの入力の大部分がFalseを返すならば、それらはより長くかかります。checkEqual2
とcheckEqual3
の場合、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
シーケンス(反復可能ではない)に対して機能する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
最も簡単でエレガントな方法は次のとおりです。
all(x==myList[0] for x in myList)
(はい、これはnullリストでも動作します!これはpythonが遅延セマンティクスを持つ数少ないケースの1つだからです。)
パフォーマンスに関しては、これは可能な限り早い時点で失敗するため、漸近的に最適です。
セット比較作業
len(set(the_list)) == 1
set
を使用すると、重複しているすべての要素が削除されます。
リストをセットに変換できます。セットは重複できません。したがって、元のリストのすべての要素が同一の場合、セットには1つの要素しかありません。
if len(sets.Set(input_list)) == 1
// input_list has all identical elements.
それが価値があるもののために、これは最近 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言い換えれば、私はその解決策を思いついたことに対して信用を取ることはできません - また、findingitについて信用することもできません。
リストをセットに変換すると、重複した要素は削除されます。したがって、変換された集合の長さが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
これは、入力リストの最初の要素を、リスト内の他のすべての要素と比較(等価)します。すべてが等しい場合は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]に値を代入することができます。
これは別のオプションです。長いリストではlen(set(x))==1
より高速です(ショートサーキットを使用します)。
def constantList(x):
return x and [x[0]]*len(x) == x
これは簡単な方法です。
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)
もう少し読みやすいものに興味があるなら(もちろん効率的ではありません)、
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
これが「最もピトニック」であることを疑うが、しかしのようなもの:
>>> 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であれば、それは同一の要素を持ち、そうでなければ、リスト内の要素は同一ではありません。
list1 = [1,1,1]
len(set(list1))
>1
list1 = [1,2,3]
len(set(list1)
>3
reduce()
をlambda
と一緒に使用することについて。これは私が個人的に他のいくつかの答えよりもずっと良いと思う実用的なコードです。
reduce(lambda x, y: (x[1]==y, y), [2, 2, 2], (True, 2))
すべての項目が同じであるかどうかにかかわらず、最初の値がブール値であるトリプルを返します。
すべての要素が最初の要素と等しいかどうかを確認してください。
np.allclose(array, array[0])
私はやる:
not any((x[i] != x[i+1] for i in range(0, len(x)-1)))
any
は、True
条件が見つかるとすぐに反復可能オブジェクトの検索を停止します。
またはnumpyのdiffメソッドを使う:
import numpy as np
def allthesame(l):
return np.unique(l).shape[0]<=1
そして呼び出すために:
print(allthesame([1,1,1]))
出力:
本当
地図とラムダが使える
lst = [1,1,1,1,1,1,1,1,1]
print all(map(lambda x: x == lst[0], lst[1:]))
あるいは、numpyのdiff
メソッドを使用してください。
import numpy as np
def allthesame(l):
return np.all(np.diff(l)==0)
そして呼び出すために:
print(allthesame([1,1,1]))
出力:
True
def allTheSame(i):
j = itertools.groupby(i)
for k in j: break
for k in j: return False
return True
「all」を持たないPython 2.4で動作します。
>>> 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"
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)))
純粋な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だけであれば、それらは同じであったはずです。
if len(set(my_list)) == 1:
できるよ:
reduce(and_, (x==yourList[0] for x in yourList), True)
Pythonでoperator.and_
のような演算子をインポートできるようになるのはかなり面倒です。 python3以降、functools.reduce
もインポートする必要があります。
(このメソッドは、等しくない値が見つかっても壊れませんが、リスト全体を調べ続けるため、使用しないでください。ここでは完全性のための回答として記載されています。)
.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