2009-09-30 24 views
8

Tôi có một danh sách bằng Python mà tôi tạo ra như một phần của chương trình. Tôi có một giả định mạnh mẽ rằng đây là tất cả khác nhau, và tôi kiểm tra điều này với một khẳng định.Cách nhiệt tình nhất để đảm bảo rằng tất cả các thành phần của danh sách là khác nhau?

Đây là cách tôi làm điều đó bây giờ:

Nếu có hai yếu tố:

try: 
    assert(x[0] != x[1]) 
except: 
    print debug_info 
    raise Exception("throw to caller") 

Nếu có ba:

try: 
    assert(x[0] != x[1]) 
    assert(x[0] != x[2]) 
    assert(x[1] != x[2]) 
except: 
    print debug_info 
    raise Exception("throw to caller") 

Và nếu tôi đã từng phải làm điều này với bốn yếu tố tôi sẽ phát điên.

Có cách nào tốt hơn để đảm bảo rằng tất cả các yếu tố trong danh sách là duy nhất không?

Trả lời

26

Có lẽ một cái gì đó như thế này:

if len(x) == len(set(x)): 
    print "all elements are unique" 
else: 
    print "elements are not unique" 
+0

câu trả lời Rất thông minh – foosion

+2

Bạn chỉ có thể lưu trữ chúng trong một tập ở nơi đầu tiên để đảm bảo rằng tất cả họ đều độc đáo. Hoặc lưu trữ chúng trong một bộ, nhưng trước khi thêm vào các thiết lập kiểm tra cho các thành viên. Nhưng điều này chắc chắn hoạt động nếu bạn không có quyền kiểm soát định dạng đầu vào. –

+0

bộ không nhất thiết phải giữ lại thứ tự, điều này có thể quan trọng. –

7

Làm thế nào về điều này:

if len(x) != len(set(x)): 
    raise Exception("throw to caller") 

này giả định rằng các yếu tố trong x là hashable.

2

Hy vọng rằng tất cả các mục trong chuỗi của bạn đều không thay đổi - nếu không, bạn sẽ không thể gọi số set theo thứ tự.

>>> set(([1,2], [3,4])) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unhashable type: 'list' 

Nếu bạn làm có các mục có thể thay đổi, bạn không thể băm các mục và bạn sẽ khá nhiều phải kiểm tra liên tục thông qua danh sách:

def isUnique(lst): 
    for i,v in enumerate(lst): 
     if v in lst[i+1:]: 
      return False 
    return True 

>>> isUnique(([1,2], [3,4])) 
True 
>>> isUnique(([1,2], [3,4], [1,2])) 
False 
1

Khi bạn tạo danh sách, bạn có thể kiểm tra xem giá trị đã tồn tại chưa, ví dụ:

if x in y: 
    raise Exception("Value %s already in y" % x) 
else: 
    y.append(x) 

lợi ích của việc này là biến xung đột sẽ được báo cáo.

0

Bạn có thể xử lý danh sách để tạo ra một tiếng-to-be-độc đáo bản sao:

def make_unique(seq): 
    t = type(seq) 
    seen = set() 
    return t(c for c in seq if not (c in seen or seen.add(c))) 

Hoặc nếu các yếu tố seq không hashable:

def unique1(seq): 
    t = type(seq) 
    seen = [] 
    return t(c for c in seq if not (c in seen or seen.append(c))) 

Và điều này sẽ giữ những vật dụng theo thứ tự (bỏ qua các bản sao, tất nhiên).

18

Câu trả lời phổ biến nhất là O (N) (tốt! -) nhưng, như @Paul và @Mark chỉ ra, chúng yêu cầu các mục của danh sách phải có thể băm. Cả hai cách tiếp cận được đề xuất của @Paul và @ Mark cho các mục không thể khắc phục đều là chung nhưng lấy O (N bình phương) - nghĩa là, rất nhiều.

Nếu các mục trong danh sách của bạn không thể băm nhưng có thể so sánh, bạn có thể làm tốt hơn ... đây là một cách tiếp cận luôn hoạt động nhanh nhất có thể do bản chất của các mục trong danh sách.

import itertools 

def allunique(L): 
    # first try sets -- fastest, if all items are hashable 
    try: 
    return len(L) == len(set(L)) 
    except TypeError: 
    pass 
    # next, try sort -- second fastest, if items are comparable 
    try: 
    L1 = sorted(L) 
    except TypeError: 
    pass 
    else: 
    return all(len(list(g))==1 for k, g in itertools.groupby(L1)) 
    # fall back to the slowest but most general approach 
    return all(v not in L[i+1:] for i, L in enumerate(L)) 

này là O (N) trong đó có tính khả thi (tất cả các mục hashable), O (N log N) làm dự trữ thường gặp nhất (một số mặt hàng unhashable, nhưng tất cả có thể so sánh), O (N vuông), nơi không thể tránh khỏi (một số mục không thể sửa chữa được, ví dụ: dicts, và một số không thể so sánh, ví dụ như số phức).

Cảm hứng cho mã này xuất phát từ một công thức cũ bởi Tim Peters tuyệt vời, khác biệt bằng cách sản xuất danh sách các mặt hàng độc đáo (và cũng cách đây không lâu) set không phải xung quanh - nó phải sử dụng dict. ..! -), nhưng về cơ bản phải đối mặt với các vấn đề giống hệt nhau.

+0

Tôi nhớ Tim. Phải mời anh ta ăn trưa sớm thôi. – holdenweb

+0

Heh, tôi nhớ anh ấy nhiều hơn (nó đã lâu hơn!), Nhưng tôi đoán nó không thực tế nếu một trong hai chúng tôi bay thẳng ra bờ biển chỉ để ăn trưa ;-). –

+0

Ý của bạn là "v không phải trong L [i + 1:] cho v, i trong liệt kê (L)'? – chepner

0

Tôi sẽ sử dụng này:

mylist = [1,2,3,4] 
is_unique = all(mylist.count(x) == 1 for x in mylist) 
+0

'O (n ** 2)', phải không? – SilentGhost

Các vấn đề liên quan