Kiểm tra xem tất cả các phần tử trong danh sách có phải là duy nhất không


104

Cách tốt nhất (tốt nhất theo cách thông thường) để kiểm tra xem tất cả các phần tử trong danh sách có phải là duy nhất không?

Cách tiếp cận hiện tại của tôi sử dụng a Counterlà:

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

Tôi có thể làm tốt hơn không?

Câu trả lời:


164

Không phải là hiệu quả nhất, nhưng thẳng thắn và ngắn gọn:

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

Có lẽ sẽ không tạo ra nhiều khác biệt cho danh sách ngắn.


Đây là những gì tôi cũng làm. Có lẽ không hiệu quả cho danh sách lớn mặc dù.
tkerwin

Không nhất thiết, điều đó sẽ thực thi phần thân của điều kiện nếu danh sách có các phần tử lặp lại ("#do something" trong ví dụ).
yan

2
Đủ công bằng, giải pháp tốt. Tôi đang xử lý hầu như không <500 phần tử, vì vậy điều này sẽ làm những gì tôi muốn.
user225312

4
Đối với những lo lắng về hiệu quả với danh sách dài, điều này hiệu quả cho các danh sách dài mà thực sự độc đáo (nơi mà tất cả các yếu tố cần kiểm tra). Các giải pháp thoát sớm mất nhiều thời gian hơn (lâu hơn khoảng gấp đôi trong các thử nghiệm của tôi) cho các danh sách thực sự duy nhất. Vì vậy, ... nếu bạn mong đợi hầu hết các danh sách của mình là duy nhất, hãy sử dụng giải pháp kiểm tra độ dài tập hợp đơn giản này. Nếu bạn mong đợi hầu hết các danh sách của mình KHÔNG phải là duy nhất, hãy sử dụng giải pháp thoát sớm. Việc sử dụng cái nào tùy thuộc vào trường hợp sử dụng của bạn.
Russ

Câu trả lời này là tốt đẹp. Tuy nhiên, hãy cẩn thận ở đây: len(x) > len(set(x))là True khi các phần tử trong xKHÔNG phải là duy nhất. Tiêu đề của câu hỏi này hỏi hoàn toàn ngược lại: "Kiểm tra xem tất cả các phần tử trong danh sách có phải là duy nhất hay không"
WhyWhat

95

Đây là một hai lớp lót cũng sẽ thoát sớm:

>>> 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

Nếu các phần tử của x không thể băm, thì bạn sẽ phải sử dụng danh sách cho 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 sạch và không lặp lại toàn bộ danh sách nếu không cần thiết.
Kos

@ paul-mcguire: Bạn có sẵn sàng cấp phép đoạn mã này theo giấy phép tương thích với Apache 2.0 không (ví dụ: Apache 2, 2/3-line BSD, MIT, X11, zlib). Tôi muốn sử dụng nó trong một dự án Apache 2.0 Tôi đang sử dụng, và bởi vì điều khoản cấp phép StackOverflow của là fubar , tôi yêu cầu bạn là tác giả gốc.
Ryan Parman

Tôi đã đưa ra mã khác bằng cách sử dụng giấy phép MIT, vì vậy nó phù hợp với tôi cho đoạn mã này. Bất cứ điều gì đặc biệt tôi cần phải làm?
PaulMcG

21

Một giải pháp thoát sớm có thể là

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

tuy nhiên đối với những trường hợp nhỏ hoặc nếu việc thoát ra ngoài sớm không phải là trường hợp phổ biến thì tôi mong đợi len(x) != len(set(x))là phương pháp nhanh nhất.


Tôi chấp nhận câu trả lời khác vì tôi không đặc biệt tìm kiếm tối ưu hóa.
user225312

2
Bạn có thể rút ngắn điều này bằng cách đặt dòng sau đây sau s = set()...return not any(s.add(x) if x not in s else True for x in g)
Andrew Clark

Bạn có thể giải thích lý do tại sao bạn mong đợi len(x) != len(set(x))sẽ nhanh hơn mức này nếu việc thoát ra ngoài sớm không phổ biến? Không phải là cả hai phép toán O (len (x)) ? ( xdanh sách ban đầu ở đâu)
Chris Redford

Ồ, tôi hiểu rồi: phương thức của bạn không phải là O (len (x)) vì bạn kiểm tra if x in sbên trong vòng lặp for O (len (x)) .
Chris Redford

14

cho tốc độ:

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

12

Làm thế nào về việc thêm tất cả các mục vào một tập hợp và kiểm tra độ dài của nó?

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

1
Trả lời một giây sau yan, ouch. Ngắn và ngọt. Bất kỳ lý do tại sao không sử dụng giải pháp này?
jasonleonhard 19/09/17

Không phải tất cả các chuỗi (đặc biệt là máy phát điện) đều hỗ trợ len().
PaulMcG

9

Thay thế cho a set, bạn có thể sử dụng a dict.

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

9
Tôi thấy hoàn toàn không có lợi khi sử dụng một câu lệnh trên một tập hợp. Có vẻ phức tạp hóa mọi thứ một cách không cần thiết.
metasoarous

3

Một cách tiếp cận hoàn toàn khác, sử dụng sắp xếp và phân nhóm:

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

Nó yêu cầu một sự sắp xếp, nhưng thoát khỏi giá trị lặp lại đầu tiên.


băm nhanh hơn sắp xếp
IceArdor

Đến đây để đăng cùng một giải pháp bằng cách sử dụng groupbyvà tìm thấy câu trả lời này. Tôi thấy điều này thanh lịch nhất, vì đây là một biểu thức duy nhất và hoạt động với các công cụ tích hợp mà không yêu cầu bất kỳ biến hoặc câu lệnh lặp bổ sung nào.
Lars Blumberg

1
Nếu danh sách của bạn chứa các đối tượng tùy ý mà không sắp xếp được, bạn có thể sử dụng id()chức năng để sắp xếp chúng như thế này là một điều kiện tiên quyết cho groupby()công việc:groupby(sorted(seq), key=id)
Lars Blumberg

3

Đây là một phiên bản O (N 2 ) đệ quy cho vui:

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

2

Đây là một hàm thoát sớm đệ quy:

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)    

Nó đủ nhanh đối với tôi mà không cần sử dụng các chuyển đổi kỳ lạ (chậm) trong khi có cách tiếp cận theo kiểu chức năng.


1
H in Tthực hiện tìm kiếm tuyến tính và T = L[1:]sao chép phần đã cắt của danh sách, vì vậy điều này sẽ chậm hơn nhiều so với các giải pháp khác đã được đề xuất trên các danh sách lớn. Tôi nghĩ đó là O (N ^ 2), trong khi hầu hết những cái khác là O (N) (bộ) hoặc O (N log N) (giải pháp dựa trên phân loại).
Blckknght

1

Còn cái này thì sao

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

0

Bạn có thể sử dụng cú pháp của Yan (len (x)> len (set (x))), nhưng thay vì set (x), hãy xác định một hàm:

 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

và làm len (x)> len (f5 (x)). Điều này sẽ nhanh chóng và cũng là để bảo toàn trật tự.

Mã ở đó được lấy từ: http://www.peterbe.com/plog/uniqifiers-benchmark


chức năng f5 này sẽ chậm hơn so với sử dụng bộ được tối ưu hóa tốt hơn cho tốc độ. Mã này bắt đầu bị phá vỡ khi danh sách trở nên thực sự lớn do hoạt động "nối thêm" tốn kém. với danh sách lớn như x = range(1000000) + range(1000000), chạy set (x) nhanh hơn f5 (x). Để không là một yêu cầu trong câu hỏi nhưng ngay cả chạy được sắp xếp (set (x)) vẫn nhanh hơn là hơn f5 (x)
OkezieE

0

Sử dụng cách tiếp cận tương tự trong khung dữ liệu Pandas để kiểm tra xem nội dung của cột có chứa các giá trị duy nhất hay không:

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

Đối với tôi, điều này xảy ra ngay lập tức trên một biến int trong khung ngày chứa hơn một triệu hàng.


0

tất cả câu trả lời ở trên đều tốt nhưng tôi thích sử dụng all_uniqueví dụ từ 30 giây của python

bạn cần sử dụng set()trên danh sách đã cho để loại bỏ các bản sao, so sánh độ dài của nó với độ dài của danh sách.

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

nó trả về Truenếu tất cả các giá trị trong một danh sách phẳng unique, Falsenếu không

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

-3

Đối với người ăn xin:

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

Tôi thích câu trả lời này, chỉ vì nó hiển thị khá tốt những mã bạn không phải viết khi sử dụng một bộ. Tôi sẽ không gắn nhãn nó là "dành cho người mới bắt đầu", vì tôi tin rằng những người mới bắt đầu nên học cách thực hiện nó một cách đúng đắn trước; nhưng tôi đã gặp một số nhà phát triển chưa có kinh nghiệm, những người đã quen viết mã như vậy bằng các ngôn ngữ khác.
cessor
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.