リスト内のすべてのアイテムが同じかどうかを判断する1000 + 1つの方法

人生では、それを知っているかどうかにかかわらず、常に選択肢があります。 コーディングでも同じことが起こります。 特定のタスクにアプローチする方法はたくさんあります。 最初にこれらの方法を検討したり、それらについて知らなかったりするかもしれませんが、それらは存在します。 プログラマーになることは、言語とコードを書くプロセスを知っているだけではありません。 非常に多くの場合、これはあなたが今まで考えたことのないことを考慮しても、あなた自身の最も創造的なバージョンであることを意味します。 そして、このノートでは、自己紹介をしたいと思います。 こんにちは 私の名前はアレックスです。私はCheckiOの創設者であり 、このプロジェクトの創造的な側面に長い間取り組んでいます。



画像






私たちのユーザーはコーディングの分野でさまざまなレベルの知識と経験を持っているため、問題を解決するための標準的でより明白なアプローチをよく目にします。 しかしときどき、私は言語のこれまで知られていなかった微妙さを再び研究することを余儀なくされるほどユニークで珍しい解決策に出くわします。



この記事では、非常に単純なタスクの1つに対するいくつかの解決策を検討したいと思いますが、これは私の意見では最も興味深いものです。 このミッションでは、配列のすべての要素の値が同じかどうかを判断する関数を記述する必要があります。



1.頭に浮かぶ最初の決定の1つは、ソース要素のリストの長さと、最初の要素がリストに含まれる回数を比較することです。 これらの値が等しい場合、リストは同じ要素で構成されます。 リストが空かどうかを確認するチェックもあります。この場合、Trueを返す必要もあるためです。



def all_the_same(elements): if len(elements) < 1: return True return len(elements) == elements.count(elements[0])
      
      





または、より短いバージョン:



 def all_the_same(elements): return len(elements) < 1 or len(elements) == elements.count(elements[0])
      
      





2.このソリューションは、Pythonの便利な機能-比較演算子だけでリストを比較する機能-「==」を使用しました(他のプログラミング言語とは異なり、これはそれほど単純ではありません)。 仕組みを見てみましょう。



 >>> [1, 1, 1] == [1, 1, 1] True >>> [1, 1, 0] == [0, 1, 1] False
      
      





この言語のもう1つの機能は、リストに数値を乗算する機能を提供することです。この操作の結果は、指定された回数だけすべての要素がコピーされるリストになります。 いくつか例を示します。



 >>> [1] * 3 [1, 1, 1] >>> [1] * 5 [1, 1, 1, 1, 1] >>> [1] * 0 [] >>> [1, 2] * 3 [1, 2, 1, 2, 1, 2]
      
      





したがって、簡単な解決策に行くことができます-元の配列の最初の要素の配列にこの元の配列の長さを掛けると、この配列のすべての要素が同じ場合、元の配列を再度取得する必要があります。



 def all_the_same(elements): if not elements: return True return [elements[0]] * len(elements) == elements
      
      





前の場合と同様に、このソリューションを短縮できます。



 def all_the_same(elements): return not elements or [elements[0]] * len(elements) == elements
      
      





3.このソリューションでは、標準のset()関数が使用されました。 この関数は、定義上、すべての要素が一意である必要があるセットにオブジェクトを変換します。 次のようになります。



 >>> elements = [1, 2, 5, 1, 5, 3, 2] >>> set(elements) {1, 2, 3, 5}
      
      





最終的に結果セットが1または0の要素で構成される場合、元のリストではすべての要素が同じか空であったことを意味します。 ソリューションは次のようになります。



 def all_the_same(elements): return len(set(elements)) in (0, 1)
      
      





または:



 def all_the_same(elements): return len(set(elements)) <= 1
      
      





NumPyモジュールでも同様のアプローチを使用できます。このモジュールには次のように機能する一意の()関数があります。



 >>> from numpy import unique >>> a = [1, 2, 1, 2, 3, 1, 1, 1, 1] >>> unique(a) [1 2 3]
      
      





ご覧のとおり、彼女の作品はset()の作品に非常に似ていますが、この場合のみです

オブジェクトのタイプが変更されます-リストはリストのままです。 この関数を使用したソリューションは次のようになります。



 from numpy import unique def all_the_same(elements): return len(unique(elements)) <= 1
      
      





4.次に、非常に独創的なソリューションの例を示しますさらに、このタスクの名前は、標準のPython関数-all ()を使用して再生されます。 all()関数は、転送されたリスト内のすべてのアイテムがTrueの場合、Trueを返します。 例:



 >>> all([1, 2, 0, True]) False #(0  true) >>> all([1, 2, None, True]) False #(None  true) >>> all([1, 2, False, True]) False >>> all([1, 2, 0.1, True]) True
      
      





まず、変数firstにはリストの最初の要素の値が割り当てられ、restは最初を除く他のすべての要素のリストです。 次に、リストの残りの要素が元のリストの最初の要素と等しいかどうかに応じて、値trueまたはfalseがタプルthe_sameに追加されます。 その後、the_sameが「True」要素のみで構成される場合、all()関数はTrueを返し、タプル内に少なくとも1つの「False」要素がある場合はFalseを返します。



 def all_the_same(elements): try: first, *rest = elements except ValueError: return True the_same = (x == first for x in rest) return all(the_same)
      
      





ValueError例外は、配列が空の場合にのみ発生します。 しかし、私たちはチェックをより身近なものにすることができます。



 def all_the_same(elements): if not elements: return True first, *rest = elements the_same = (x == first for x in rest) return all(the_same)
      
      





5.次のソリューションは、前のソリューションと非常によく似ています。 元のリストの最初の要素とその他の要素は、イテレータを使用して分離されます。 iter()関数は渡されたリストからイテレータを作成し、next()関数はそこから次の要素(つまり、最初の呼び出しの最初の要素)を取得します。 elおよびfirstの要素を出力すると、次のように表示されます。



 >>> el = iter([1, 2, 3]) >>> first = next(el, None) >>> print(first) 1 >>> for i in el: >>> print(i) 2 3
      
      





その他の点では、このソリューションは前のソリューションと似ていますが、リストが空かどうかを確認する必要がなくなりました。



 def all_the_same(elements): el = iter(elements) first = next(el, None) return all(element == first for element in el)
      
      





6.この問題を解決する創造的なアプローチの1つは、要素の再配置です。 アイテムを交換し、このためリストが変更されていないことを確認します。 これにより、リスト内のすべてのアイテムが同じであることがわかります。 以下に、このアプローチの例をいくつか示します。



 def all_the_same(elements): return elements[1:] == elements[:-1]
      
      





そして



 def all_the_same(elements): return elements == elements[1:] + elements[:1]
      
      





zip()関数を使用して配列を要素ごとに比較することもできます 。 次のソリューションでこれを検討してください。



7. zip()関数は、最も短いオブジェクトが終了するまで、1つのオブジェクトの各i番目の要素を残りのi番目の要素と結合します。



 >>> x = [1, 2, 3] >>> y = [10, 11] >>> list(zip(x, y)) [(1, 10), (2, 11)]
      
      





ご覧のとおり、xは3つの要素で構成されていますが、最短のオブジェクト(この場合はy)は2つの要素のみで構成されているため、2つしか使用されていません。



以下のソリューションは次のように機能します。最初に、2番目のリストが作成されます(要素[1:])。これは元のリストと同じですが、最初の要素はありません。 次に、これら2つのリストの項目が1つずつ比較され、そのような各比較の結果として、TrueまたはFalseが取得されます。 その後、all()関数は、このTrueとFalseのセットを処理した結果を返します。



 def all_the_same(elements): return all(x == y for x, y in zip(elements, elements[1:]))
      
      





元のリストがelements = [2、2、2、3]であるとします。 次に、zip()を使用して、完全なリスト([2、2、2、3])と最初の要素のないリスト([2、2、3])を次のように結合します:[(2、2)、(2、2 )、(2、3)]、要素間の比較は、セット[True、True、False]をall()関数に渡します。その結果、すべての要素が元のリストと同じではないため、Falseが返されます。



8.次のソリューションは非常に好奇心が強いことが判明しました。 この方法で動作するgroupby()イテレータを使用しました-各i番目の要素を(i-1)番目と比較し、要素が等しい場合は先に進み、等しくない場合は要素(i-1)を最終リストに残します次のアイテムとの比較を続けます。 実際には、次のようになります。



 >>> from itertools import groupby >>> elements = [1, 1, 1, 2, 1, 1, 1, 2] >>> for key, group in groupby(elements): >>> print(key) 1 2 1 2
      
      





ご覧のとおり、次の位置の要素とは異なる要素のみが残りました(要素[0]、要素[1]、要素[4]、および要素[5]は除外されました)。



このソリューションでは、groupby()イテレータを使用して、元のリストの次の要素が前の要素と異なるたびに、関数はリストに1を追加します。 したがって、最初のリストで0個の要素またはすべての要素が等しい場合、合計(sum(groupby(elements)の_の1))は0または1になります。つまり、ソリューションで示されるように、2未満です。



 from itertools import groupby def all_the_same(elements): return sum(1 for _ in groupby(elements)) < 2
      
      





9.標準のPythonモジュールの1つであるコレクションを使用する別の創造的なソリューション。 Counterは、ソースリスト内の各要素の数に関する情報を入力する辞書を作成します。 仕組みを見てみましょう。



 >>> from collections import Counter >>> a = [1, 1, 1, 2, 2, 3] >>> Counter(a) Counter({1: 3, 2: 2, 3: 1})
      
      





したがって、この辞書の長さが2以上の場合、元のリストには少なくとも2つの異なる要素があり、すべての要素が同じではありません。



 def all_the_same(elements): from collections import Counter return not len(list(Counter(elements))) > 1
      
      





10.このソリューションは、ソリューションNo. 7と同じロジックで構築されていますが、関数eq()およびstarmap()が使用されます。 それらがどのように機能するかを見てみましょう:



 >>> from operator import eq >>> eq(1, 2) False
      
      





本質的に、eq()関数は「==」と同じです-2つのオブジェクトを比較し、等しい場合はTrueを、そうでない場合はFalseを返します(eq-同等の略)。 ただし、関数はオブジェクトであり、たとえば、引数として別の関数に渡すことができることに注意してください。これは、以下で説明するソリューションで行われました。



starmap()関数は、オブジェクトのリストに別の関数を適用するイテレーターを作成します。 オブジェクトがすでにタプルにグループ化されている場合に使用されます。 例:



 >>> import math >>> from itertools import starmap >>> list(starmap(math.pow, [(1, 2), (3, 4)])) [1.0, 81.0]
      
      





ご覧のように、一度指定されたmath.pow()関数は、両方のオブジェクトセットにstarmap()関数のために2回適用されました(1 ** 2 = 1.0、3 ** 4 = 81.0)



簡略化すると、この例のstarmap()関数はループとして表すことができます。



 import math elements = [(1, 2), (3, 4)] result = [] for i in elements: result.append(math.pow(i[0], i[1]))
      
      





前述の関数を使用したソリューションは次のようになります。



 from operator import eq from itertools import starmap def all_the_same(elements): return all(starmap(eq, zip(elements, elements[1:])))
      
      





おわりに



そこで、最も単純なパズルの1つに関連するいくつかの賢明な決定を見ました。 あらゆる要望がありますが、ユーザーが他の興味深い複雑な問題を解決するために使用する独自のアプローチの数を説明する手掛かりさえありません。 私がこの記事を書いたときと同じように、この記事を読んで楽しんでいることを願っています。 フィードバックをお待ちしております。 これは役に立ちましたか? この問題をどのように解決しますか?



ブログ「The Mouse Vs. 」に掲載された記事「リスト内のすべての要素がPythonで同じかどうかを判断する」の翻訳 Python




All Articles