2012-04-26 30 views
11

Tôi muốn chuyển qua danh sách nhiều lần (N lần) qua một trình lặp, để không thực sự lưu trữ N bản sao của danh sách trong bộ nhớ. Có cách xây dựng hoặc thanh lịch để thực hiện việc này mà không cần viết trình tạo của riêng tôi không?Có một cách thanh lịch để chu kỳ thông qua một danh sách N lần thông qua lặp (như itertools.cycle nhưng giới hạn các chu kỳ)?

Lý tưởng nhất, itertools.cycle (my_list) sẽ có đối số thứ hai để giới hạn số lần nó lặp lại ... than ôi, không may mắn như vậy.

+0

Tôi tin rằng việc nhân danh sách với số nguyên không đủ tốt, phải không? '[1, 2, 3] * 4' – C2H5OH

+0

@ C2H5OH Điều đó sẽ tạo ra 4 bản sao nông của danh sách (N bản sao là những gì không muốn). – Darthfett

+0

@ Darthfett: Thật vậy. Đó là lý do tại sao nó là một bình luận. Nhưng bạn sẽ đồng ý rằng đó là giải pháp thanh lịch nhất: -P – C2H5OH

Trả lời

14
import itertools 
itertools.chain.from_iterable(itertools.repeat([1, 2, 3], 5)) 

Itertools là một thư viện tuyệt vời. :)

+0

Đây là một câu trả lời khá rõ ràng, không liên quan đến máy phát điện/trình lặp của riêng tôi (mặc dù câu trả lời của Matt Anderson cho thấy rằng không quá lộn xộn), và là một các câu trả lời đầu tiên thỏa mãn câu hỏi của tôi. Vì vậy, tôi chấp nhận nó. Cảm ơn!! – JJC

7
itertools.chain.from_iterable(iter(L) for x in range(N)) 
6

Đối với trường hợp đặc biệt mà bạn cần phải lặp qua danh sách nhiều lần, điều này không quá tệ.

Nó tạo ra một danh sách các tài liệu tham khảo n-my_list, vì vậy nếu n là rất lớn nó là tốt hơn để sử dụng câu trả lời Darthfelt của

>>> import itertools as it 
>>> it.chain(*[my_list]*n) 
+0

Tôi đã cố gắng tránh trùng lặp danh sách (hoặc tham chiếu đến nó) trong bộ nhớ, nếu không chỉ: mylist * n sẽ có đủ điều kiện. :-) Tuy nhiên, cảm ơn cho đầu vào của bạn. Chỉ cần được rõ ràng, là có bất kỳ sự khác biệt giữa việc mở rộng danh sách thông qua các nhà điều hành danh sách * và nhân với n so với chỉ nhân danh sách bằng n? – JJC

+0

@JJC, 'mylist * n' tạo danh sách với các phần tử' len (mylist) * n) '. Đối với câu trả lời này, bạn chỉ cần tạo danh sách các phần tử 'n', do đó, tùy thuộc vào' len (danh sách) 'và 'n' điều này có thể tạo ra sự khác biệt rất lớn –

+0

Tôi hiểu rằng [1,2,3,4] * 2 sẽ tạo danh sách 8 yếu tố. Vì vậy, bạn đang nói rằng * [1,2,3,4] * 2 chỉ tạo ra hai yếu tố? Xin lỗi, tôi đang bối rối.Cảm ơn. – JJC

5

Tất cả các câu trả lời khác là tuyệt vời. Một giải pháp khác là sử dụng islice. Điều này cho phép bạn làm gián đoạn chu kỳ tại bất kỳ điểm:

>>> from itertools import islice, cycle 
>>> l = [1, 2, 3] 
>>> list(islice(cycle(l), len(l) * 3)) 
[1, 2, 3, 1, 2, 3, 1, 2, 3] 
>>> list(islice(cycle(l), 7)) 
[1, 2, 3, 1, 2, 3, 1] 
+0

Tốt, tôi không biết islice làm việc với các giá trị cho 'stop' lớn hơn độ dài của vòng lặp có thể lặp lại. – Darthfett

+1

@ Darthfett, đúng vậy. Nhưng điều đó không liên quan ở đây; các iterable trả về bởi 'chu kỳ' là vô hạn dài. – senderle

3

Bạn nói rằng bạn không muốn viết máy phát điện riêng của bạn, nhưng một biểu thức máy phát điện có lẽ sẽ là cách dễ nhất và hiệu quả nhất để thực hiện những gì bạn' sau đó. Nó không yêu cầu bất kỳ cuộc gọi chức năng hoặc nhập khẩu của bất kỳ mô-đun. itertools là một mô-đun tuyệt vời, nhưng có lẽ không cần thiết trong trường hợp này?

some_list = [1, 2, 3] 
cycles = 3 
gen_expr = (elem for _ in xrange(cycles) for elem in some_list) 

hoặc chỉ

(elem for _ in xrange(3) for elem in [1, 2, 3]) 

hoặc

for elem in (e for _ in xrange(3) for e in [1, 2, 3]): 
    print "hoo-ray, {}!".format(elem) 
+0

Tôi thích các biểu thức máy phát điện này. Chúng nhỏ gọn hơn tôi nhận ra rằng chúng là kiểu mẫu này. Tôi sẽ cung cấp cho câu trả lời tín dụng để @ Darthfett, kể từ khi tôi yêu cầu một máy phát điện không tự cuộn, nhưng nếu tôi có thể chấp nhận hai, tôi sẽ chấp nhận của bạn cũng (và có lẽ những người khác :-)) Cảm ơn! – JJC

1

@ câu trả lời Darthfett được ghi nhận như một itertools recipes:

from itertools import chain, repeat 

def ncycles(iterable, n): 
    "Returns the sequence elements n times" 
    return chain.from_iterable(repeat(tuple(iterable), n)) 


list(ncycles(["a", "b"], 3)) 
# ['a', 'b', 'a', 'b', 'a', 'b'] 

Để thuận tiện, tôi thêm rằng các thư viện more_itertools thực hiện công thức này (và nhiều công thức khác) cho bạn:

import more_itertools as mit 

list(mit.ncycles(["a", "b"], 3)) 
# ['a', 'b', 'a', 'b', 'a', 'b'] 
+0

Cảm ơn, nhưng điều này giống với câu trả lời được chấp nhận của Darthfett. – JJC

+0

Vâng, chúng tương đương nhau. Tôi đã chỉnh sửa để làm rõ rằng mã của anh ta là một công thức 'itertools' hiện có (không sớm hơn Python 2.3). Tôi đăng tùy chọn này để chứng minh thư viện của bên thứ ba triển khai các công thức nấu ăn này và xóa bỏ việc triển khai thủ công nếu muốn. Cảm ơn bạn. – pylang

+1

Tuyệt. Gói more_itertools trông rất tiện dụng. Cảm ơn bạn đã chia sẻ nó. – JJC

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