Bạn không cần chuyển đổi cả hai list
s thành set
s, chỉ một. Tôi nghĩ rằng bỏ qua các chuyển đổi không cần thiết làm cho nó dễ đọc hơn và thanh lịch.
Vì vậy, một trong hai:
set(a).intersection(b)
Hoặc:
s = set(a)
any(e in s for e in b)
Sau này có lợi thế là ngắn mạch càng sớm càng nó tìm thấy một trận đấu, và tốt hơn thể hiện logic, và trở về True
hoặc False
thay vì không phải là một falsey hoặc falsey set
, nhưng đó là hai dòng thay vì một, nếu điều đó làm phiền bạn. Tôi không có ý tưởng cho dù lợi thế này hủy bỏ chi phí đặt vòng lặp bên trong một biểu thức máy phát điện thay vì bên trong một hàm C.
Kết quả hoạt động với list
s này nhỏ gần như vô nghĩa, vì vậy hãy thử điều này:
In [373]: a=[random.choice(string.ascii_lowercase) for _ in range(10000)]
In [374]: b=[random.choice(string.ascii_lowercase) for _ in range(10000)]
In [375]: %timeit(set(a))
10000 loops, best of 3: 180 us per loop
In [376]: s=set(a) # since all versions need to do this
In [391]: %timeit(s & set(b))
1000000 loops, best of 3: 178 us per loop
In [392]: %timeit(s.intersection(b))
1000000 loops, best of 3: 247 us per loop
In [393]: %timeit(discard(e in s for e in b))
1000000 loops, best of 3: 550 ns per loop
In [394]: %timeit(any(e in s for e in b))
1000000 loops, best of 3: 749 ns per loop
In [395]: %timeit(any(e in a for e in b))
1000000 loops, best of 3: 1.42 us per loop
Để đưa những con số tất cả ở quy mô nano giây, thêm trở lại trong chi phí của set(a)
rằng tất cả nhưng cuối cùng cần, và so sánh các thử nghiệm giống nhau từ ba phiên bản Python (CPython cổ phiếu của Apple 2.7.2, python.org CPython 3.3.0, Homebrew PyPy 1.9.0/2.7.2, tất cả các bản Mac 64 bit):
CP272 CP330 PyPy
s & set(b) 358000 316000 180500
s.intersection(b) 427000 459000 180900
discard(genexp) 180550 157341 90094
any(genexp) 180749 157334 90208
any(list-genexp) 1420 686 960
Bây giờ tôi nghĩ về điều này, điều này có ý nghĩa tổng thể. Tỷ lệ nhận được một vụ va chạm khá sớm là rất cao, do đó, chi phí chuyển đổi toàn bộ điều để một bộ thống trị tất cả mọi thứ.
Điều đó có nghĩa là chúng tôi cần một thử nghiệm mới, với 10.000 giá trị duy nhất. Hãy lặp lại bài kiểm tra, với điều này:
In [29]: a, b = list(range(10000)), list(range(10000))
In [30]: random.shuffle(a)
In [31]: random.shuffle(b)
CP272 CP330 PyPy
s & set(b) 1277000 1168000 1141000
s.intersection(b) 1165000 1117000 2520000
discard(genexp) 1699000 1271000 770000
any(genexp) 389800 344543 320807
any(list-genexp) 62000 10400 1520
Đây là hợp lý hơn. Và họ vẫn có ý nghĩa. Nếu bạn so sánh cùng 10000 yếu tố ngẫu nhiên xáo trộn, bạn phải đi bao xa? Không đủ xa để làm cho chi phí của set
-xác định một trong hai danh sách đáng làm, ít hơn nhiều cả hai!
Vì vậy, chúng ta hãy thử một trường hợp có các không trận đấu:
In [43]: a=list(range(10000, 20000))
CP272 CP330 PyPy
s & set(b) 751000 770000 733000
s.intersection(b) 466000 530000 1920000
discard(genexp) 1246000 985000 749000
any(genexp) 1269000 966000 893000
any(list-genexp) 185000000 176000000 5870000
Tôi không có ý tưởng như thế nào PyPy đã làm người cuối cùng quá nhanh, nhưng khác hơn thế, không ngạc nhiên ở đây.
Vì vậy, cái nào là tốt nhất?
Rõ ràng, nếu bạn mong đợi rất nhiều va chạm, bạn muốn tránh làm bộ bất cứ khi nào có thể - nhưng nếu bạn mong đợi ít va chạm, bạn muốn tạo ít nhất một bộ. Nếu bạn không có ý tưởng, tôi nghĩ rằng đặt cược an toàn nhất là any(genexp)
- tồi tệ nhất là ít hơn 3x là tốt nhất, và nếu có cơ hội tỷ lệ va chạm cao, nó sẽ nhanh hơn rất nhiều. Nhưng bạn có thể nhìn vào những con số và xem cho chính mình.
Hoặc, tốt hơn, tất nhiên, dành thời gian cho tất cả dữ liệu thử nghiệm thực mà bạn mong đợi gặp phải.
Are các yếu tố duy nhất trong mỗi danh sách? Nếu vậy bạn có thể làm điều này khá đơn giản bằng cách sử dụng 'bộ'. –
Có, các phần tử trong danh sách là duy nhất. – Amyth
@Mike: Chờ ... tại sao bạn không thể làm điều này với các bộ ngay cả khi các phần tử _weren't_ duy nhất? Bạn mất thông tin rằng một phần tử tồn tại nhiều lần, nhưng nếu tất cả những gì bạn quan tâm là yếu tố tồn tại, bạn không cần thông tin đó. (Và, nếu bạn đã làm, bạn luôn có thể chỉ sử dụng một 'Counter' thay vì một' bộ' để giữ lại nó.) – abarnert