ตรวจสอบว่าองค์ประกอบทั้งหมดในรายการไม่ซ้ำกันหรือไม่


104

อะไรคือวิธีที่ดีที่สุด (ที่ดีที่สุดในแบบทั่วไป) ในการตรวจสอบว่าองค์ประกอบทั้งหมดในรายการไม่ซ้ำกันหรือไม่

แนวทางปัจจุบันของฉันโดยใช้ a 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

ไม่จำเป็นที่จะดำเนินการเนื้อหาของเงื่อนไขหากรายการมีองค์ประกอบที่ซ้ำกัน ("# do something" ในตัวอย่าง)
ยัน

2
พอใช้ทางออกที่ดี ฉันจัดการแทบไม่ถึง 500 องค์ประกอบดังนั้นสิ่งนี้ควรทำในสิ่งที่ฉันต้องการ
user225312

4
สำหรับผู้ที่กังวลเกี่ยวกับประสิทธิภาพของรายการแบบยาวสิ่งนี้มีประสิทธิภาพสำหรับรายการแบบยาวที่ไม่ซ้ำกันจริง ๆ (ซึ่งทุกองค์ประกอบต้องมีการตรวจสอบ) วิธีแก้ปัญหาก่อนกำหนดใช้เวลานานขึ้น (ประมาณ 2 เท่าในการทดสอบของฉัน) สำหรับรายการที่ไม่ซ้ำกันจริงๆ ดังนั้น ... หากคุณคาดว่ารายการส่วนใหญ่ของคุณจะไม่ซ้ำกันให้ใช้โซลูชันการตรวจสอบความยาวชุดง่ายๆนี้ หากคุณคาดว่ารายการส่วนใหญ่ของคุณจะไม่ซ้ำใครให้ใช้วิธีแก้ปัญหาก่อนกำหนด จะใช้อันไหนขึ้นอยู่กับกรณีการใช้งานของคุณ
Russ

คำตอบนี้ดี อย่างไรก็ตามโปรดระวังที่นี่: len(x) > len(set(x))เป็นจริงเมื่อองค์ประกอบในxไม่ซ้ำกัน ชื่อของคำถามนี้ถามตรงข้าม: "การตรวจสอบถ้าองค์ประกอบทั้งหมดในรายการเป็นที่ไม่ซ้ำกัน"
WhyWhat

96

นี่คือสองซับที่จะออกก่อน:

>>> 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 สะอาดและไม่วนซ้ำทั้งรายการหากไม่จำเป็น
คอส

@ paul-mcguire: คุณยินดีที่จะให้สิทธิ์ใช้งานข้อมูลโค้ดนี้ภายใต้ใบอนุญาตที่เข้ากันได้กับ Apache 2.0 (เช่น Apache 2, 2/3-line BSD, MIT, X11, zlib) ฉันต้องการใช้ในโปรเจ็กต์ Apache 2.0 ที่ฉันใช้และเนื่องจากเงื่อนไขการให้สิทธิ์การใช้งานของ StackOverflow เป็นfubarฉันจึงขอให้คุณเป็นผู้เขียนต้นฉบับ
Ryan Parman

ฉันได้ใส่รหัสอื่น ๆ โดยใช้ใบอนุญาต MIT ดังนั้นมันจึงเหมาะกับฉันสำหรับตัวอย่างข้อมูลนี้ มีอะไรพิเศษที่ฉันต้องทำ?
PaulMcG

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

2
คุณสามารถย่อให้สั้นลงได้โดยใส่บรรทัดต่อไปนี้หลัง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))ถึงจะเร็วกว่านี้หากการออกก่อนกำหนดไม่ใช่เรื่องปกติ การดำเนินการทั้งสองอย่างO (len (x))ไม่ใช่หรือ ( xรายการเดิมอยู่ที่ไหน)
Chris Redford

โอ้ฉันเห็น: วิธีการของคุณไม่ใช่O (len (x))เพราะคุณตรวจสอบif x in sภายในO (len (x))สำหรับลูป
Chris Redford


12

วิธีการเพิ่มรายการทั้งหมดในชุดและตรวจสอบความยาว

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

1
ตอบหนึ่งวินาทีหลังจากแยนอุ๊ย สั้นและหวาน มีเหตุผลใดบ้างที่ไม่ควรใช้โซลูชันนี้
jasonleonhard

ไม่ลำดับทั้งหมด len()(เครื่องกำเนิดไฟฟ้าโดยเฉพาะอย่างยิ่งการสนับสนุน)
PaulMcG

9

ทางเลือกอื่นสำหรับ a setคุณสามารถใช้ไฟล์dict.

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

9
ฉันไม่เห็นประโยชน์เลยที่จะใช้คำสั่งในชุด ดูเหมือนจะซับซ้อนโดยไม่จำเป็น
metasoarous

3

อีกวิธีหนึ่งโดยใช้การเรียงลำดับและ groupby:

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

ต้องมีการเรียงลำดับ แต่ออกจากค่าที่ซ้ำกันครั้งแรก


การแฮชเร็วกว่าการเรียงลำดับ
IceArdor

มาที่นี่เพื่อโพสต์วิธีแก้ปัญหาเดียวกันโดยใช้groupbyและพบคำตอบนี้ ฉันพบว่าสิ่งนี้สง่างามที่สุดเนื่องจากเป็นนิพจน์เดียวและใช้งานได้กับเครื่องมือในตัวโดยไม่ต้องใช้ตัวแปรเพิ่มเติมหรือคำสั่งวนซ้ำ
Lars Blumberg

1
หากรายการของคุณมีวัตถุตามอำเภอใจซึ่งไม่สามารถจัดเรียงได้คุณสามารถใช้id()ฟังก์ชันเพื่อจัดเรียงได้เนื่องจากเป็นข้อกำหนดเบื้องต้นในgroupby()การทำงาน:groupby(sorted(seq), key=id)
Lars 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


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)รันเซต (x) เร็วกว่า f5 (x) คำสั่งซื้อไม่ใช่ข้อกำหนดในคำถาม แต่แม้จะเรียกใช้การเรียงลำดับ (set (x)) ก็ยังเร็วกว่า f5 (x)
OkezieE

0

ใช้แนวทางที่คล้ายกันในดาต้าเฟรมของ Pandas เพื่อทดสอบว่าเนื้อหาของคอลัมน์มีค่าที่ไม่ซ้ำกันหรือไม่:

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

สำหรับฉันสิ่งนี้เกิดขึ้นทันทีกับตัวแปร int ใน dateframe ที่มีมากกว่าล้านแถว


0

คำตอบทั้งหมดข้างต้นดี แต่ฉันชอบใช้all_uniqueตัวอย่างจากpython 30 วินาที

คุณจำเป็นต้องใช้set()ในรายการที่กำหนดเพื่อลบรายการที่ซ้ำกันเปรียบเทียบความยาวกับความยาวของรายการ

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

ก็จะส่งกลับTrueถ้าค่าทั้งหมดในรายการแบนunique, Falseมิฉะนั้น

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.