2010-04-23 41 views
11

Tôi đang tìm cách lặp lại đầu tiên trên các mục n đầu tiên của một lần lặp lại (upd: không phải danh sách trong trường hợp phổ biến, cho các danh sách mọi thứ đều tầm thường) và điều quan trọng là phải làm điều này càng nhanh càng tốt. Đây là cách tôi làm điều đó ngay bây giờ:Lặp lại nhanh chóng trên các mục đầu tiên n của một lần lặp (không phải danh sách) trong python

count = 0 
for item in iterable: 
do_something(item) 
count += 1 
if count >= n: break 

Không có vẻ gọn gàng với tôi. Một cách khác để thực hiện việc này là:

for item in itertools.islice(iterable, n): 
    do_something(item) 

Điều này có vẻ tốt, câu hỏi này có đủ nhanh để sử dụng với một số (các) trình tạo không? Ví dụ:

pair_generator = lambda iterable: itertools.izip(*[iter(iterable)]*2) 
for item in itertools.islice(pair_generator(iterable), n): 
so_something(item) 

Nó có chạy đủ nhanh so với phương pháp đầu tiên không? Có cách nào dễ dàng hơn để làm điều đó không?

+3

Cách duy nhất để trả lời "đủ nhanh" là để chuẩn đó cho mình. –

+0

Xem thêm: http://stackoverflow.com/questions/2688079/how-to-iterate-over-the-first-n-elements-of-a-list – outis

+0

Tại sao "khá quan trọng để làm điều này nhanh như khả thi"? Bạn có thể biện minh điều này với kết quả pstats cho một trường hợp sử dụng thực tế? Tôi nghi ngờ rằng giải pháp của bạn với 'islice' sẽ thực sự chứng minh giải pháp hiệu quả nhất hợp lý, nhưng tất nhiên chúng ta không biết mà không có thời gian. –

Trả lời

14

for item in itertools.islice(iterable, n): là cách dễ dàng rõ ràng nhất để làm điều đó. Nó hoạt động cho các vòng lặp tùy ý và là O (n), giống như bất kỳ giải pháp lành mạnh nào.

Có thể hiểu rằng giải pháp khác có thể có hiệu suất tốt hơn; chúng tôi sẽ không biết mà không có thời gian. Tôi sẽ không khuyên bạn nên bận tâm đến thời gian trừ khi bạn profile mã của mình và tìm cuộc gọi này thành điểm phát sóng. Trừ khi nó bị chôn vùi trong một vòng lặp bên trong, nó là rất nghi ngờ rằng nó sẽ được. Tối ưu hóa sớm là gốc rễ của mọi điều ác.


Nếu tôi sẽ tìm kiếm các giải pháp thay thế, tôi sẽ nhìn vào những người như for count, item in enumerate(iterable): if count > n: break ...for i in xrange(n): item = next(iterator) .... Tôi sẽ không đoán chúng sẽ giúp ích gì, nhưng chúng dường như đáng để thử nếu chúng ta thực sự muốn so sánh mọi thứ. Nếu tôi bị kẹt trong một tình huống mà ở đó tôi đã lược tả và thấy đây là điểm phát sóng trong vòng lặp bên trong (đây có phải là tình huống của bạn không?), Tôi cũng sẽ cố gắng giảm bớt tra cứu tên từ thuộc tính islice của toàn cầu iterools thành liên kết hàm với tên cục bộ.

Đây là những điều bạn chỉ làm sau khi bạn đã chứng minh rằng họ sẽ giúp đỡ. Mọi người cố gắng làm cho họ nhiều lần khác. Nó không giúp làm cho chương trình của họ đáng tin cậy nhanh hơn; nó chỉ làm cho chương trình của họ tồi tệ hơn.

+1

Cảm ơn rất nhiều vì câu trả lời, nó đã giúp tôi rất nhiều! – martinthenext

+0

Vâng, liệt kê uning trông khá tốt với tôi quá! Đối với hồ sơ và tìm điểm nóng, đây không phải là trường hợp của tôi, tôi chỉ mong đợi một số vòng trong mã của tôi có số lần lặp lại rất lớn, đó là lý do tại sao tôi đã hỏi một câu hỏi. Bây giờ tôi nhận được nó - đây là một sai lầm để thử tối ưu hóa trên giai đoạn này, tôi đã hoàn thành mã và kiểm tra nó, và chỉ sau đó tối ưu hóa mọi thứ, nếu cần thiết. Cảm ơn một lần nữa vì sự giúp đỡ của bạn. – martinthenext

1

Danh sách? Hãy thử

for k in mylist[0:n]: 
    # do stuff with k 

bạn cũng có thể sử dụng một sự hiểu biết nếu bạn cần phải

my_new_list = [blah(k) for k in mylist[0:n]] 
+0

vâng, tôi hiểu rồi. sai tiêu đề, xin lỗi, xấu của tôi. – martinthenext

2

Nếu đó là một danh sách thì bạn có thể sử dụng cắt:

list[:n] 
6

itertools có xu hướng trở thành giải pháp nhanh nhất, khi áp dụng trực tiếp.

Rõ ràng, cách duy nhất để kiểm tra là để chuẩn - ví dụ, tiết kiệm trong aaa.py

import itertools 

def doit1(iterable, n, do_something=lambda x: None): 
    count = 0 
    for item in iterable: 
    do_something(item) 
    count += 1 
    if count >= n: break 

def doit2(iterable, n, do_something=lambda x: None): 
    for item in itertools.islice(iterable, n): 
     do_something(item) 

pair_generator = lambda iterable: itertools.izip(*[iter(iterable)]*2) 

def dd1(itrbl=range(44)): doit1(itrbl, 23) 
def dd2(itrbl=range(44)): doit2(itrbl, 23) 

và xem ...:

$ python -mtimeit -s'import aaa' 'aaa.dd1()' 
100000 loops, best of 3: 8.82 usec per loop 
$ python -mtimeit -s'import aaa' 'aaa.dd2()' 
100000 loops, best of 3: 6.33 usec per loop 

rõ ràng, itertools nhanh hơn ở đây - điểm chuẩn với dữ liệu của riêng bạn để xác minh.

BTW, tôi tìm thấy timeit MUCH có thể sử dụng được từ dòng lệnh, vì vậy đó là cách tôi luôn sử dụng nó - sau đó chạy "thứ tự độ lớn" của vòng lặp cho loại tốc độ bạn đang cố gắng đo lường , là 10, 100, 1000, v.v. - ở đây, để phân biệt một micro giây và một nửa khác biệt, một trăm nghìn vòng là đúng.

+1

lạ, nó chỉ là chống lại trực giác của tôi cplusplus'ish để xem một giải pháp đơn giản chạy chậm hơn một gọn gàng. python là ngôn ngữ tuyệt vời nhất. đây là một bổ sung tuyệt vời cho lời khuyên của Mike Graham không phải để tối ưu hóa sớm. tôi đoán quy tắc chung là viết gọn gàng, không nghĩ về thời gian chạy. – martinthenext

+1

@martin, cá nhân, tôi nghĩ rằng một _lot_ về thời gian chạy (chủ yếu là về big-O cho khả năng mở rộng) - nhưng, nói chung, hầu hết các thành ngữ Pythonic thường là những người đã được tối ưu hóa nhất, bởi vì họ thường là những người mà chúng tôi Python có xu hướng quan tâm nhất (Hettinger, tác giả của itertools và các phần nhanh khác của Python, đã hoạt động khá tích cực trong lĩnh vực đó trong những năm gần đây, như Peters trong những năm trước đó, nhưng nó khá chung chung hiện tượng trong cộng đồng Python-committer). –

2

Bạn có thể sử dụng enumerate để viết về cơ bản cùng một vòng lặp bạn có, nhưng trong một cách Pythonic đơn giản hơn:

 
for idx, val in enumerate(iterableobj): 
    if idx > n: 
     break 
    do_something(val) 
+0

Tùy chọn này đã được thảo luận ở trên, trông giống như một lựa chọn tốt, nhưng tôi nghĩ 'islice' là tốt hơn vì nó không yêu cầu bất kỳ biến bổ sung nào trong thân vòng lặp, làm cho nó trông rõ ràng hơn với tôi – martinthenext

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