2012-01-20 11 views
17

Nói rằng tôi có một danh sách:Cycle qua danh sách bắt đầu từ một yếu tố nào đó

l = [1, 2, 3, 4] 

Và tôi muốn chu kỳ thông qua nó. Thông thường, nó sẽ làm một cái gì đó như thế này,

1, 2, 3, 4, 1, 2, 3, 4, 1, 2... 

Tôi muốn có thể bắt đầu tại một điểm nhất định trong chu kỳ, không nhất thiết là chỉ mục, nhưng có lẽ khớp với một phần tử. Giả sử tôi muốn bắt đầu ở bất kỳ phần tử nào trong danh sách ==4, thì đầu ra sẽ là,

4, 1, 2, 3, 4, 1, 2, 3, 4, 1... 

Làm cách nào để thực hiện điều này?

Trả lời

20

Nhìn vào itertools module. Nó cung cấp tất cả các chức năng cần thiết.

from itertools import cycle, islice, dropwhile 

L = [1, 2, 3, 4] 

cycled = cycle(L) # cycle thorugh the list 'L' 
skipped = dropwhile(lambda x: x != 4, cycled) # drop the values until x==4 
sliced = islice(skipped, None, 10) # take the first 10 values 

result = list(sliced) # create a list from iterator 
print(result) 

Output:

[4, 1, 2, 3, 4, 1, 2, 3, 4, 1] 
7

Sử dụng toán tử số học mod. Giả sử bạn đang bắt đầu từ vị trí k, sau đó k cần được cập nhật như thế này:

k = (k + 1) % len(l) 

Nếu bạn muốn bắt đầu từ một yếu tố nhất định, chứ không phải chỉ mục, bạn có thể luôn luôn nhìn nó như k = l.index(x) trong đó x là mong muốn mục.

2
import itertools as it 
l = [1, 2, 3, 4] 
list(it.islice(it.dropwhile(lambda x: x != 4, it.cycle(l)), 10)) 
# returns: [4, 1, 2, 3, 4, 1, 2, 3, 4, 1] 

nên iterator bạn muốn là:

it.dropwhile(lambda x: x != 4, it.cycle(l)) 
+4

'4 .__ cmp__' cũng làm việc thay vì lambda xấu xí –

+0

@gnibbler Nó sẽ làm để đưa '4' trong ngoặc' (4) .__ cmp__'. Nếu không nó không hoạt động (ít nhất là trong Python 2.7.2). Và với dấu ngoặc đơn, nó trông không đẹp. – ovgolovin

+0

@gnibbler Và như của Python 3 nó sẽ sử dụng '__eq__' thay vì' __cmp__' (không có '__cmp__' như của phiên bản 3). – ovgolovin

2

Tôi không phải là một fan hâm mộ lớn của nhập khẩu các module khi bạn có thể làm mọi thứ bằng cách riêng của bạn trong một vài dòng. Đây là giải pháp của tôi mà không cần nhập khẩu:

def cycle(my_list, start_at=None): 
    start_at = 0 if start_at is None else my_list.index(start_at) 
    while True: 
     yield my_list[start_at] 
     start_at = (start_at + 1) % len(my_list) 

Điều này sẽ trả về một trình lặp (vô hạn) lặp lại danh sách của bạn. Để có được phần tử tiếp theo trong chu kỳ, bạn phải sử dụng câu lệnh next:

>>> it1 = cycle([101,102,103,104]) 
>>> next(it1), next(it1), next(it1), next(it1), next(it1) 
(101, 102, 103, 104, 101) # and so on ... 
>>> it1 = cycle([101,102,103,104], start_at=103) 
>>> next(it1), next(it1), next(it1), next(it1), next(it1) 
(103, 104, 101, 102, 103) # and so on ... 
+4

'itertools' được viết bằng' C'. Vì vậy, nó khá nhanh ngoài sự hùng hồn của nó. – ovgolovin

0

Một lựa chọn khác lạ là đi xe đạp thông qua danh sách có thể được thực ngược. Ví dụ:

# Run this once 
myList = ['foo', 'bar', 'baz', 'boom'] 
myItem = 'baz' 

# Run this repeatedly to cycle through the list 
if myItem in myList: 
    myItem = myList[myList.index(myItem)-1] 
    print myItem