2016-02-02 12 views
12

Nếu có một danh sách như vậy:cách nhanh các chuỗi qua trong một danh sách

shops=['A','B','C','D'] 

Và muốn tạo danh sách mới như sau (tôi qua mỗi phần tử với mỗi khác và tạo ra một chuỗi nơi phần đầu tiên là alphanumerically trước giây):

['A-B', 'A-C', 'A-D'] 

['A-B', 'B-C', 'B-D'] 

['A-C', 'B-C', 'C-D'] 

['A-D', 'B-D', 'C-D'] 

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

for a in shops: 
    cons = [] 
    for b in shops: 
     if a!=b: 
      con = [a,b] 
      con = sorted(con, key=lambda x: float(x)) 
      cons.append(con[0]+'-'+con[1]) 
    print(cons) 

Tuy nhiên, đây là pr chậm cho các danh sách lớn (ví dụ: 1000 nơi tôi có 1000 * 999 * 0,5 kết quả đầu ra). Tôi đang tìm kiếm một cách hiệu quả hơn để làm điều này?

Tôi có thể đã sử dụng mệnh đề if-else cho sắp xếp, ví dụ:

for a in shops: 
    cons = [] 
    for b in shops: 
     if a<b: 
      cons.append(a+"-"+b) 
     elif a>b: 
      cons.append(b+"-"+a) 
    print(cons) 

nào, tôi đã không tính thời gian được nêu ra - tuy nhiên tôi nghĩ rằng chính chậm xuống là gấp đôi cho vòng

+0

Tại sao không '('A_B', 'A_C', 'B_C')'? – Kasramvd

+2

'khóa = lambda x: float (x)' là như nhau - chỉ chậm hơn - như 'key = float' –

+1

Tôi không điều bạn có thể nhận được sự phức tạp tổng thể của thuật toán này xuống, vì bạn phải tạo tất cả những kết hợp đó. Bạn chỉ có thể thực hiện điều chỉnh vi mô (như không định nghĩa các lambda không cần thiết). Tuy nhiên: Bạn cần những kết hợp nào ở vị trí đầu tiên? Có thể có một cách tốt hơn, ví dụ: chỉ tạo các kết hợp hoặc không có sắp xếp. –

Trả lời

9

Bạn có thể tạo một danh sách lồng nhau-hiểu với một số kiểm tra thêm:

>>> shops=['A','B','C','D'] 
>>> [["-".join((min(a,b), max(a,b))) for b in shops if b != a] for a in shops] 
[['A-B', 'A-C', 'A-D'], 
['A-B', 'B-C', 'B-D'], 
['A-C', 'B-C', 'C-D'], 
['A-D', 'B-D', 'C-D']] 

Lưu ý rằng điều này có thể sẽ không thể nhanh hơn nhiều so với mã của bạn, như bạn vẫn phải tạo ra tất cả những kết hợp. Trong thực tế, bạn có thể biến nó thành một biểu hiện phát, vì vậy các yếu tố không được tạo ra cùng một lúc nhưng chỉ có "khi cần thiết":

gen = (["-".join((min(a,b), max(a,b))) for b in shops if b != a] for a in shops) 
for item in gen: 
    print(item) 

Cập nhật: Tôi đã làm một số phân tích thời gian sử dụng IPython của %timeit. Hóa ra việc triển khai thứ hai của bạn là nhanh nhất. Thử nghiệm với một danh sách 100 dây (map(str, range(100))) và sau khi chuyển từng phương pháp thành máy phát điện.

In [32]: %timeit list(test.f1())   # your first implementation 
100 loops, best of 3: 13.5 ms per loop 

In [33]: %timeit list(test.f2())   # your second implementation 
1000 loops, best of 3: 1.63 ms per loop 

In [34]: %timeit list(test.g())   # my implementation 
100 loops, best of 3: 3.49 ms per loop 

Bạn có thể tăng tốc độ nó lên bằng cách sử dụng một cách đơn giản if/else thay vì min/max, như trong thực hiện thứ 2 của bạn, sau đó họ về bình đẳng nhanh.

(["-".join((a,b) if a < b else (b,a)) for b in shops if b != a] for a in shops) 
+0

Cảm ơn rất nhiều! Sự khác biệt giữa việc sử dụng biểu thức trình tạo hoặc sử dụng hàm và trả về với lợi nhuận là gì? Tôi thường làm điều cũ. – mptevsion

+0

@mptevsion Chúng tương đương nhau. Một biểu thức máy phát điện là một hàm có năng suất như là một sự hiểu biết danh sách là một hàm trả về một danh sách. –

+0

@mptevsion 'yield' là tổng quát hơn. Đó là một biểu thức và bạn có thể chuyển các giá trị vào hàm bằng cách sử dụng phương thức 'send'. Điều này không thể được thực hiện trong một biểu thức máy phát điện. Hãy thử nó: 'def f(): x = yield 0; năng suất x' sau đó làm 'a = f(); tiếp theo (a); a.send (1); tiếp theo (a) '. – Bakuriu

2

Dựa trên những gì bạn nói:

tôi qua mỗi phần tử với nhau và tạo chuỗi nơi phần đầu tiên là có dạng chữ và số trước số thứ hai

Bạn có thể sử dụng 2 kết hợp như sau:

>>> form itertools import combinations 
>>> list(combinations(['_'.join(i) for i in combinations(shops,2)],3) 
...) 
[('A_B', 'A_C', 'A_D'), ('A_B', 'A_C', 'B_C'), ('A_B', 'A_C', 'B_D'), ('A_B', 'A_C', 'C_D'), ('A_B', 'A_D', 'B_C'), ('A_B', 'A_D', 'B_D'), ('A_B', 'A_D', 'C_D'), ('A_B', 'B_C', 'B_D'), ('A_B', 'B_C', 'C_D'), ('A_B', 'B_D', 'C_D'), ('A_C', 'A_D', 'B_C'), ('A_C', 'A_D', 'B_D'), ('A_C', 'A_D', 'C_D'), ('A_C', 'B_C', 'B_D'), ('A_C', 'B_C', 'C_D'), ('A_C', 'B_D', 'C_D'), ('A_D', 'B_C', 'B_D'), ('A_D', 'B_C', 'C_D'), ('A_D', 'B_D', 'C_D'), ('B_C', 'B_D', 'C_D')] 
>>> 

Lúc đầu, bạn có thể sử dụng kết hợp trong danh sách để hiểu các cặp đặt hàng và nối chúng bằng cách sử dụng str.join. Sau đó, sử dụng một kết hợp khác để tạo các bộ ba.

+1

Điều này dường như không mở rộng tốt đối với trường hợp gồm 6 phần tử trong danh sách. – Alexander

+1

Khi tôi hiểu câu hỏi, danh sách con đầu tiên phải có A trong mỗi kết hợp, B thứ hai, rồi C và D, mỗi chữ cái với mỗi chữ cái khác, được sắp xếp theo thứ tự bảng chữ cái. –

+0

@tobias_k Vâng, đó là những gì rõ ràng trong sản lượng dự kiến, nhưng không phải trong những gì OP đã nói. – Kasramvd

4

Nếu danh sách được sắp xếp và không có trùng lặp, bạn có thể theo dõi vị trí của mình trong danh sách để tránh phải so sánh để nhận đơn đặt hàng.

from itertools import chain, islice 

combos = [] 
for i, s in enumerate(shops): 
    combo = ['{0}-{1}'.format(a, b) for a, b in chain(
     ((c, s) for c in islice(shops, None, i), 
     ((s, c) for c in islice(shops, i+1))] 
    combos.append(combo) 

EDIT: cập nhật để sử dụng máy phát điện

+0

Tôi nghĩ rằng việc tạo tất cả các danh sách tạm thời đó sẽ chậm chạp, nhưng (khi được chuyển đổi thành máy phát), tốc độ này nhanh như các lần triển khai thứ hai của OP hoặc máy phát điện của tôi. Tuy nhiên, đối với các danh sách lớn, tôi dường như có kết quả khác. Đối với 'cửa hàng = map (str, range (10))' các kết quả bằng nhau, nhưng với 'map (str, range (100))' kết quả của bạn khác nhau, không thể biết được ... –

+0

@ tobias_k: Điều này giả định danh sách được sắp xếp. Khi bạn có số> = 10 dưới dạng chuỗi, cửa hàng sẽ không được sắp xếp chính xác ngay từ đầu. (Tôi đã có ý tưởng tương tự, nhưng Brendan đánh tôi với nó :) –

+0

@AleksiTorhamo Bạn nói đúng, chỉ cần kiểm tra: Sự khác biệt đến từ các cửa hàng đang được sắp xếp khác nhau trong việc triển khai của chúng tôi. –

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