Bir listedeki tüm öğelerin benzersiz olup olmadığını kontrol etme


104

Bir listedeki tüm öğelerin benzersiz olup olmadığını kontrol etmenin en iyi yolu (geleneksel yöntemde olduğu gibi) nedir?

A kullanan mevcut yaklaşımım Counter:

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

Daha iyisini yapabilir miyim?

Yanıtlar:


164

En verimli değil, açık ve öz:

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

Muhtemelen kısa listeler için pek bir fark yaratmayacaktır.


Ben de bunu yapıyorum. Muhtemelen büyük listeler için verimli değildir.
tkerwin

Listede yinelenen öğeler varsa (örnekteki "#do birşeyler") koşullu ifadenin gövdesini çalıştırması gerekmez.
yan

2
Yeterince adil, iyi çözüm. 500'den az elementle uğraşıyorum, bu yüzden bu istediğimi yapmalı.
user225312

4
Uzun listeleri ile verimlilik endişe olanlar için, bu ise (tüm unsurları kontrol gerek olduğu) aslında benzersiz uzun listeleri için etkili. Gerçekten benzersiz listeler için erken çıkış çözümleri daha uzun sürer (testlerimde kabaca 2 kat daha uzun). Yani ... Listelerinizin çoğunun benzersiz olmasını bekliyorsanız, bu basit set uzunluk kontrol çözümünü kullanın. Listelerinizin çoğunun benzersiz OLMAMASINI bekliyorsanız, bir erken çıkış çözümü kullanın. Hangisini kullanacağınız, kullanım durumunuza bağlıdır.
Russ

Bu cevap güzel. Ancak, burada dikkatli olalım: len(x) > len(set(x))içindeki öğeler xbenzersiz OLMADIĞINDA doğrudur . Bu Sorunun başlığı tam tersini sorar: "Denetleme Bir listedeki tüm unsurlar ise şunlardır benzersiz"
WhyWhat

96

İşte erken çıkış yapacak iki hatlı bir yol:

>>> 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'in öğeleri hashable değilse, o zaman aşağıdakiler için bir listeye başvurmanız gerekir 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 temizlenir ve gerekmediği takdirde tüm liste boyunca yinelenmez.
Kos

@ paul-mcguire: Bu kod parçacığını Apache 2.0 uyumlu bir lisans (örneğin, Apache 2, 2/3-line BSD, MIT, X11, zlib) altında lisanslamak ister misiniz? Bunu kullandığım bir Apache 2.0 projesinde kullanmak istiyorum ve StackOverflow'un lisans koşulları fubar olduğundan , sizden orijinal yazar olarak soruyorum.
Ryan Parman

MIT lisansını kullanarak başka bir kod koydum, bu yüzden bu benim için bu snippet için çalışıyor. Yapmam gereken özel bir şey var mı?
PaulMcG

21

Erken çıkış çözümü olabilir

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

ancak küçük vakalar için veya erken çıkış yaygın bir durum değilse, o zaman len(x) != len(set(x))en hızlı yöntem olmasını beklerim.


Diğer cevabı özellikle optimizasyon aramadığım için kabul ettim.
user225312

2
Bunu aşağıdaki satırı sonrasına koyarak kısaltabilirsiniz s = set()...return not any(s.add(x) if x not in s else True for x in g)
Andrew Clark

len(x) != len(set(x))Erken çıkış yaygın değilse neden bundan daha hızlı olmayı beklediğinizi açıklayabilir misiniz ? Her iki işlem de O (len (x)) değil mi? ( xorijinal liste nerede )
Chris Redford

Oh, anlıyorum: yönteminiz O (len (x)) değil çünkü döngü if x in siçin O (len (x)) 'in içini kontrol ediyorsunuz .
Chris Redford

15

hız için:

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

12

Tüm girişleri bir sete ekleyip uzunluğunu kontrol etmeye ne dersiniz?

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

1
Yan, ah, bir saniye sonra cevap verdi. Kısa ve güzel. Bu çözümü kullanmamak için herhangi bir neden var mı?
jasonleonhard

Tüm diziler (özellikle oluşturucular) desteklenmez len().
PaulMcG

9

A'ya alternatif olarak set, bir dict.

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

9
Bir set yerine dikte kullanmanın kesinlikle hiçbir avantajı görmüyorum. Gereksiz yere işleri karmaşıklaştırıyor gibi görünüyor.
metasoarous

3

Tamamen sıralanmış ve groupby kullanarak başka bir yaklaşım:

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

Bir sıralama gerektirir, ancak ilk tekrarlanan değerden çıkar.


karma oluşturma, sıralamadan daha hızlı
IceArdor

Aynı çözümü kullanarak göndermek için buraya geldim groupbyve bu cevabı buldum. Bunu çok zarif buluyorum, çünkü bu tek bir ifade ve herhangi bir ekstra değişken veya döngü ifadesi gerektirmeden yerleşik araçlarla çalışıyor.
Lars Blumberg

1
Listeniz sıralanamayan rasgele nesneler içeriyorsa, id()bunları sıralamak için işlevi kullanabilirsiniz, çünkü bu groupby()çalışmak için bir önkoşuldur :groupby(sorted(seq), key=id)
Lars Blumberg

3

İşte eğlence için özyinelemeli bir O (N 2 ) sürümü:

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

2

İşte özyinelemeli bir erken çıkış işlevi:

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)    

İşlevsel tarzda bir yaklaşıma sahipken garip (yavaş) dönüşümler kullanmadan benim için yeterince hızlı.


1
H in Tdoğrusal bir arama yapar T = L[1:]ve listenin dilimlenmiş bölümünü kopyalar, böylece bu, büyük listelerde önerilen diğer çözümlerden çok daha yavaş olacaktır. Sanırım O (N ^ 2), diğerlerinin çoğu O (N) (kümeler) veya O (N log N) (sıralama tabanlı çözümler).
Blckknght

1

Buna ne dersin

def is_unique(lst):
    if not lst:
        return True
    else:
        return Counter(lst).most_common(1)[0][1]==1

0

Yan'ın sözdizimini (len (x)> len (set (x))) kullanabilirsiniz, ancak set (x) yerine bir işlev tanımlayın:

 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

ve len (x)> len (f5 (x)) yapın. Bu hızlı olacak ve aynı zamanda siparişi koruyacak.

Buradaki kod şu adresten alınmıştır: http://www.peterbe.com/plog/uniqifiers-benchmark


bu f5 işlevi, hız için daha iyi optimize edilmiş olan seti kullanmaktan daha yavaş olacaktır. Bu kod, pahalı "ekleme" işlemi nedeniyle liste gerçekten büyüdüğünde bozulmaya başlar. gibi büyük listelerde x = range(1000000) + range(1000000)(x) kümesini çalıştırmak f5 (x) 'ten daha hızlıdır.
Soruda

0

Bir sütunun içeriğinin benzersiz değerler içerip içermediğini test etmek için Pandas veri çerçevesinde benzer bir yaklaşım kullanma:

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

Benim için bu, bir milyondan fazla satır içeren bir tarih çerçevesindeki bir int değişkeninde anlıktır.


0

Yukarıdaki tüm cevaplar iyi ama ben 30 saniyelik python'danall_unique örnek kullanmayı tercih ediyorum

set()Yinelenenleri kaldırmak için verilen listede kullanmanız , uzunluğunu listenin uzunluğu ile karşılaştırmanız gerekir.

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

Döndürdüğü Truedüz listedeki tüm değerleri ise unique, Falseaksi

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

-3

Yeni başlayanlar için:

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

Bu cevabı beğendim, çünkü bir set kullanırken hangi kodu yazmanız gerekmediğini oldukça iyi gösteriyor. Yeni başlayanların bunu en başta doğru şekilde yapmayı öğrenmeleri gerektiğine inandığım için bunu "yeni başlayanlar için" olarak etiketlemem; ancak başka dillerde bu tür bir kod yazmaya alışmış bazı deneyimsiz geliştiricilerle tanıştım.
cessor
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.