リスト内のすべての要素が一意であるかどうかの確認


104

リスト内のすべての要素が一意であるかどうかを確認する最良の方法(従来の方法と同様)は何ですか?

私の現在のアプローチCounterは次のとおりです:

>>> x = [1, 1, 1, 2, 3, 4, 5, 6, 2]
>>> counter = Counter(x)
>>> for values in counter.itervalues():
        if values > 1: 
            # do something

もっと上手にできる?

回答:


164

最も効率的ではありませんが、単純明快です。

if len(x) > len(set(x)):
   pass # do something

ショートリストの場合、おそらく違いはほとんどありません。


これも私がやっていることです。ただし、大きなリストではおそらく効率的ではありません。
tkerwin 2011年

必ずしもそうではありませんが、リストに繰り返し要素(例では「#do something」)がある場合は、条件の本体が実行されます。
yan

2
十分に公正で良い解決策です。私はかろうじて500未満の要素を処理しているので、これは私が望むことをするはずです。
user225312

4
長いリストの効率が心配な場合は、これ実際に一意である(すべての要素でチェックが必要な)長いリストの場合に効率的です。早期終了ソリューションでは、実際に一意のリストの場合、時間がかかります(テストでは約2倍長くなります)。そのため、リストのほとんどが一意であると予想される場合は、この単純なセット長チェックソリューションを使用してください。リストのほとんどが一意でないと予想される場合は、早期終了ソリューションを使用してください。どちらを使用するかは、ユースケースによって異なります。
ラス

この答えはいいです。ただし、ここで注意してみましょう。len(x) > len(set(x))要素xが一意でない場合はTrue です。この質問のタイトルは正反対の質問です。「リスト内のすべての要素一意であるかどうかの確認」
WhyWhat

95

これも早期終了を行う2つのライナーです:

>>> def allUnique(x):
...     seen = set()
...     return not any(i in seen or seen.add(i) for i in x)
...
>>> allUnique("ABCDEF")
True
>>> allUnique("ABACDEF")
False

xの要素がハッシュ可能でない場合は、次のリストを使用する必要がありますseen

>>> def allUnique(x):
...     seen = list()
...     return not any(i in seen or seen.append(i) for i in x)
...
>>> allUnique([list("ABC"), list("DEF")])
True
>>> allUnique([list("ABC"), list("DEF"), list("ABC")])
False

5
+1クリーン。不要な場合はリスト全体を反復しません。
Kos

@ paul-mcguire:このコードスニペットをApache 2.0互換のライセンス(Apache 2、2 / 3ラインBSD、MIT、X11、zlibなど)でライセンスしてもよろしいですか?私が使用しているApache 2.0プロジェクトでそれを使用したいのですが、StackOverflowのライセンス条項がfubarであるため、元の作者としてお願いします。
Ryan Parman 2016

私はMITライセンスを使用して他のコードを発行したので、このスニペットではそれが機能します。何か特別なことをする必要がありますか?
PaulMcG 2016

21

早期終了ソリューションは、

def unique_values(g):
    s = set()
    for x in g:
        if x in s: return False
        s.add(x)
    return True

ただし、小さなケースの場合、または早期終了が一般的なケースではない場合、私はlen(x) != len(set(x))最速の方法であることを期待します。


特に最適化を探していなかったので、私は他の答えを受け入れました。
user225312 2011年

2
あなたは後に次の行を置くことによって、これを短縮することができますs = set()...return not any(s.add(x) if x not in s else True for x in g)
アンドリュー・クラーク

len(x) != len(set(x))早期終了が一般的でない場合に、これよりも高速になると予想される理由を説明できますか?両方の操作はO(len(x))ではありませんか?(x元のリストはここにあります)
Chris Redford

ああ、なるほど。O (len(x)) forループif x in s内をチェックしているので、メソッドはO(len(x))ではありません。
Chris Redford

14

スピードのために:

import numpy as np
x = [1, 1, 1, 2, 3, 4, 5, 6, 2]
np.unique(x).size == len(x)

12

すべてのエントリをセットに追加して、その長さをチェックするのはどうですか?

len(set(x)) == len(x)

1
やぁ、1秒後に答えました。短くて甘い。このソリューションを使用しない理由は何ですか?
jasonleonhard 2017

すべてのシーケンス(特にジェネレータ)がをサポートしてlen()いるわけではありません。
PaulMcG

9

の代わりにset、を使用できますdict

len({}.fromkeys(x)) == len(x)

9
セットに対してディクテーションを使用するメリットはまったくないようです。物事を不必要に複雑にしているようです。
metasoarous

3

別のアプローチとして、sortedおよびgroupbyを使用します。

from itertools import groupby
is_unique = lambda seq: all(sum(1 for _ in x[1])==1 for x in groupby(sorted(seq)))

ソートが必要ですが、最初に繰り返された値で終了します。


ハッシュはソートよりも高速です
IceArdor 2014年

同じgroupby答えを使用して同じソリューションを投稿するためにここに来て、この答えを見つけました。これは最もエレガントです。これは単一の式であり、追加の変数やループステートメントを必要とせずに組み込みツールで動作するためです。
Lars Blumberg

1
あなたのリストがソート可能でない任意のオブジェクトが含まれている場合は、使用することができid()、これがための前提条件であるとして、それらをソートする機能をgroupby()仕事に:groupby(sorted(seq), key=id)
ラースBlumbergの

3

以下は、楽しみのための再帰的なO(N 2)バージョンです。

def is_unique(lst):
    if len(lst) > 1:
        return is_unique(s[1:]) and (s[0] not in s[1:])
    return True

2

再帰的な早期終了関数は次のとおりです。

def distinct(L):
    if len(L) == 2:
        return L[0] != L[1]
    H = L[0]
    T = L[1:]
    if (H in T):
            return False
    else:
            return distinct(T)    

関数型のアプローチをとりながら、奇妙な(遅い)変換を使わなくても十分高速です。


1
H in T線形検索を行いT = L[1:]、リストのスライスされた部分をコピーするため、これは大きなリストで提案されている他のソリューションよりもはるかに遅くなります。それはO(N ^ 2)だと思いますが、他のほとんどはO(N)(セット)またはO(N log N)(並べ替えベースのソリューション)です。
Blckknght 2013


0

Yanの構文(len(x)> len(set(x)))を使用できますが、set(x)の代わりに関数を定義します。

 def f5(seq, idfun=None): 
    # order preserving
    if idfun is None:
        def idfun(x): return x
    seen = {}
    result = []
    for item in seq:
        marker = idfun(item)
        # in old Python versions:
        # if seen.has_key(marker)
        # but in new ones:
        if marker in seen: continue
        seen[marker] = 1
        result.append(item)
    return result

そしてlen(x)> len(f5(x))を実行します。これは高速で、注文を保存することにもなります。

そこから取得されたコード:http : //www.peterbe.com/plog/uniqifiers-benchmark


このf5関数は、速度に最適化されたsetを使用するよりも遅くなります。このコードは、高価な「追加」操作のためにリストが本当に大きくなると壊れ始めます。のような大きなリストではx = range(1000000) + range(1000000)、set(x)の実行はf5(x)よりも高速です。順序は問題ではありませんが、sorted(set(x))を実行してもf5(x)より高速です
OkezieE

0

Pandasデータフレームで同様のアプローチを使用して、列の内容に一意の値が含まれているかどうかをテストします。

if tempDF['var1'].size == tempDF['var1'].unique().size:
    print("Unique")
else:
    print("Not unique")

私にとって、これは100万行を超える日付フレームのint変数で瞬時に発生します。


0

上記のすべての答えは良いですが、私all_unique30秒のpythonの例を使用することを好みます

set()重複を削除するには、指定されたリストで使用する必要があります。その長さとリストの長さを比較してください。

def all_unique(lst):
  return len(lst) == len(set(lst))

Trueフラットリストのすべての値がである場合に返されますuniqueFalseそれ以外の場合は

x = [1,2,3,4,5,6]
y = [1,2,2,3,4,5]
all_unique(x) # True
all_unique(y) # False

-3

初心者向け:

def AllDifferent(s):
    for i in range(len(s)):
        for i2 in range(len(s)):
            if i != i2:
                if s[i] == s[i2]:
                    return False
    return True

私はこの答えが好きです。それは、セットを使用するときに記述する必要のないコードがかなりよくわかるからです。「初心者向け」というラベルは付けません。なぜなら、初心者は前もって正しい方法で学習する必要があるからです。しかし、そのようなコードを他の言語で書くことに慣れている経験の浅い開発者に会いました。
cessor
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.