Làm thế nào để tôi thực hiện một for
vòng lặp hoặc một danh sách hiểu để mỗi lần lặp lại cho tôi hai yếu tố?
l = [1,2,3,4,5,6]
for i,k in ???:
print str(i), '+', str(k), '=', str(i+k)
Đầu ra:
1+2=3
3+4=7
5+6=11
Làm thế nào để tôi thực hiện một for
vòng lặp hoặc một danh sách hiểu để mỗi lần lặp lại cho tôi hai yếu tố?
l = [1,2,3,4,5,6]
for i,k in ???:
print str(i), '+', str(k), '=', str(i+k)
Đầu ra:
1+2=3
3+4=7
5+6=11
Câu trả lời:
Bạn cần một pairwise()
(hoặc grouped()
) thực hiện.
Đối với Python 2:
from itertools import izip
def pairwise(iterable):
"s -> (s0, s1), (s2, s3), (s4, s5), ..."
a = iter(iterable)
return izip(a, a)
for x, y in pairwise(l):
print "%d + %d = %d" % (x, y, x + y)
Hoặc, nói chung hơn:
from itertools import izip
def grouped(iterable, n):
"s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), (s2n,s2n+1,s2n+2,...s3n-1), ..."
return izip(*[iter(iterable)]*n)
for x, y in grouped(l, 2):
print "%d + %d = %d" % (x, y, x + y)
Trong Python 3, bạn có thể thay thế izip
bằng zip()
hàm tích hợp và thả import
.
Tất cả tín dụng cho martineau cho câu trả lời của anh ấy cho câu hỏi của tôi , tôi đã thấy điều này rất hiệu quả vì nó chỉ lặp lại một lần trong danh sách và không tạo ra bất kỳ danh sách không cần thiết nào trong quy trình.
Lưu ý : Điều này không nên nhầm lẫn với pairwise
công thức trong itertools
tài liệu riêng của Python , mang lại s -> (s0, s1), (s1, s2), (s2, s3), ...
, như được chỉ ra bởi @lazyr trong các bình luận.
Một bổ sung nhỏ cho những ai muốn kiểm tra kiểu với mypy trên Python 3:
from typing import Iterable, Tuple, TypeVar
T = TypeVar("T")
def grouped(iterable: Iterable[T], n=2) -> Iterable[Tuple[T, ...]]:
"""s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), ..."""
return zip(*[iter(iterable)] * n)
s -> (s0,s1), (s1,s2), (s2, s3), ...
itertools
chức năng công thức có cùng tên. Tất nhiên là của bạn nhanh hơn ...
izip_longest()
thay vì izip()
. Vd: list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))
-> [(1, 2), (3, 0)]
. Hi vọng điêu nay co ich.
Vâng, bạn cần bộ 2 yếu tố, vì vậy
data = [1,2,3,4,5,6]
for i,k in zip(data[0::2], data[1::2]):
print str(i), '+', str(k), '=', str(i+k)
Ở đâu:
data[0::2]
có nghĩa là tạo tập hợp con của các phần tử (index % 2 == 0)
zip(x,y)
tạo một bộ sưu tập tuple từ các tập hợp x và y cùng các phần tử chỉ mục.for i, j, k in zip(data[0::3], data[1::3], data[2::3]):
import
không phải là một trong số họ.
>>> l = [1,2,3,4,5,6]
>>> zip(l,l[1:])
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
>>> zip(l,l[1:])[::2]
[(1, 2), (3, 4), (5, 6)]
>>> [a+b for a,b in zip(l,l[1:])[::2]]
[3, 7, 11]
>>> ["%d + %d = %d" % (a,b,a+b) for a,b in zip(l,l[1:])[::2]]
['1 + 2 = 3', '3 + 4 = 7', '5 + 6 = 11']
zip
trả về một zip
đối tượng trong Python 3, không thể đăng ký được. Trước tiên, nó cần được chuyển đổi thành một chuỗi ( list
, tuple
v.v.), nhưng "không hoạt động" là một chút kéo dài.
Một giải pháp đơn giản.
l = [1, 2, 3, 4, 5, 6] cho i trong phạm vi (0, len (l), 2): in str (l [i]), '+', str (l [i + 1]), '=', str (l [i] + l [i + 1])
((l[i], l[i+1])for i in range(0, len(l), 2))
đối với một máy phát điện, có thể dễ dàng sửa đổi cho các bộ dữ liệu dài hơn.
Mặc dù tất cả các câu trả lời sử dụng zip
đều đúng, tôi thấy rằng việc tự thực hiện chức năng dẫn đến mã dễ đọc hơn:
def pairwise(it):
it = iter(it)
while True:
try:
yield next(it), next(it)
except StopIteration:
# no more elements in the iterator
return
Phần it = iter(it)
đảm bảo rằng đó it
thực sự là một trình vòng lặp, không chỉ là một vòng lặp. Nếu it
đã là một trình vòng lặp, dòng này là không có.
Sử dụng:
for a, b in pairwise([0, 1, 2, 3, 4, 5]):
print(a + b)
it
chỉ là một trình vòng lặp và không phải là một vòng lặp. Các giải pháp khác dường như dựa vào khả năng tạo hai vòng lặp độc lập cho chuỗi.
Tôi hy vọng đây sẽ là cách làm thanh lịch hơn nữa.
a = [1,2,3,4,5,6]
zip(a[::2], a[1::2])
[(1, 2), (3, 4), (5, 6)]
Trong trường hợp bạn quan tâm đến hiệu suất, tôi đã thực hiện một điểm chuẩn nhỏ (sử dụng thư viện của mình simple_benchmark
) để so sánh hiệu suất của các giải pháp và tôi đã bao gồm một chức năng từ một trong các gói của mình:iteration_utilities.grouper
from iteration_utilities import grouper
import matplotlib as mpl
from simple_benchmark import BenchmarkBuilder
bench = BenchmarkBuilder()
@bench.add_function()
def Johnsyweb(l):
def pairwise(iterable):
"s -> (s0, s1), (s2, s3), (s4, s5), ..."
a = iter(iterable)
return zip(a, a)
for x, y in pairwise(l):
pass
@bench.add_function()
def Margus(data):
for i, k in zip(data[0::2], data[1::2]):
pass
@bench.add_function()
def pyanon(l):
list(zip(l,l[1:]))[::2]
@bench.add_function()
def taskinoor(l):
for i in range(0, len(l), 2):
l[i], l[i+1]
@bench.add_function()
def mic_e(it):
def pairwise(it):
it = iter(it)
while True:
try:
yield next(it), next(it)
except StopIteration:
return
for a, b in pairwise(it):
pass
@bench.add_function()
def MSeifert(it):
for item1, item2 in grouper(it, 2):
pass
bench.use_random_lists_as_arguments(sizes=[2**i for i in range(1, 20)])
benchmark_result = bench.run()
mpl.rcParams['figure.figsize'] = (8, 10)
benchmark_result.plot_both(relative_to=MSeifert)
Vì vậy, nếu bạn muốn giải pháp nhanh nhất mà không cần phụ thuộc bên ngoài, có lẽ bạn chỉ nên sử dụng phương pháp do Johnysweb đưa ra (tại thời điểm viết nó là câu trả lời được chấp nhận và được chấp nhận nhiều nhất).
Nếu bạn không nhớ phụ thuộc bổ sung thì các grouper
từ iteration_utilities
có lẽ sẽ nhanh hơn một chút.
Một số cách tiếp cận có một số hạn chế, chưa được thảo luận ở đây.
Ví dụ: một vài giải pháp chỉ hoạt động cho các chuỗi (đó là danh sách, chuỗi, v.v.), ví dụ: các giải pháp Margus / pyanon / taskinoor sử dụng lập chỉ mục trong khi các giải pháp khác hoạt động trên bất kỳ iterable nào (đó là trình tự và trình tạo, trình lặp) như Johnysweb / mic_e / giải pháp của tôi.
Sau đó, Johnysweb cũng cung cấp một giải pháp hoạt động cho các kích thước khác ngoài 2 trong khi các câu trả lời khác thì không (không sao, iteration_utilities.grouper
cũng cho phép đặt số lượng phần tử thành "nhóm").
Sau đó, cũng có câu hỏi về những gì sẽ xảy ra nếu có một số phần tử lẻ trong danh sách. Các mặt hàng còn lại có nên được miễn nhiệm? Danh sách nên được đệm để làm cho nó thậm chí có kích thước? Các mặt hàng còn lại có nên được trả lại như là duy nhất? Câu trả lời khác không đề cập trực tiếp đến điểm này, tuy nhiên nếu tôi không bỏ qua bất cứ điều gì thì tất cả đều tuân theo cách tiếp cận rằng mục còn lại sẽ bị loại bỏ (ngoại trừ câu trả lời của người làm nhiệm vụ - điều đó thực sự sẽ gây ra Ngoại lệ).
Với grouper
bạn có thể quyết định những gì bạn muốn làm:
>>> from iteration_utilities import grouper
>>> list(grouper([1, 2, 3], 2)) # as single
[(1, 2), (3,)]
>>> list(grouper([1, 2, 3], 2, truncate=True)) # ignored
[(1, 2)]
>>> list(grouper([1, 2, 3], 2, fillvalue=None)) # padded
[(1, 2), (3, None)]
Sử dụng các lệnh zip
và iter
cùng nhau:
Tôi thấy giải pháp này sử dụng iter
khá thanh lịch:
it = iter(l)
list(zip(it, it))
# [(1, 2), (3, 4), (5, 6)]
Mà tôi tìm thấy trong tài liệu zip Python 3 .
it = iter(l)
print(*(f'{u} + {v} = {u+v}' for u, v in zip(it, it)), sep='\n')
# 1 + 2 = 3
# 3 + 4 = 7
# 5 + 6 = 11
Để khái quát cho N
các yếu tố tại một thời điểm:
N = 2
list(zip(*([iter(l)] * N)))
# [(1, 2), (3, 4), (5, 6)]
for (i, k) in zip(l[::2], l[1::2]):
print i, "+", k, "=", i+k
zip(*iterable)
trả về một tuple với phần tử tiếp theo của mỗi lần lặp.
l[::2]
trả về phần tử thứ 1, thứ 3, thứ 5, v.v. của danh sách: dấu hai chấm đầu tiên chỉ ra rằng lát cắt bắt đầu từ đầu bởi vì không có số nào phía sau nó, dấu hai chấm thứ hai chỉ cần nếu bạn muốn một bước 'trong lát cắt '(trong trường hợp này là 2).
l[1::2]
thực hiện tương tự nhưng bắt đầu trong phần tử thứ hai của danh sách để nó trả về phần tử thứ 2, thứ 4, thứ 6, v.v. của danh sách gốc .
[number::number]
hoạt động của cú pháp. hữu ích cho những người không sử dụng trăn thường xuyên
Với việc giải nén:
l = [1,2,3,4,5,6]
while l:
i, k, *l = l
print(str(i), '+', str(k), '=', str(i+k))
Đối với bất kỳ ai, điều này có thể giúp ích, đây là một giải pháp cho một vấn đề tương tự nhưng với các cặp chồng chéo (thay vì các cặp loại trừ lẫn nhau).
Từ tài liệu itertools của Python :
from itertools import izip
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
Hoặc, nói chung hơn:
from itertools import izip
def groupwise(iterable, n=2):
"s -> (s0,s1,...,sn-1), (s1,s2,...,sn), (s2,s3,...,sn+1), ..."
t = tee(iterable, n)
for i in range(1, n):
for j in range(0, i):
next(t[i], None)
return izip(*t)
bạn có thể sử dụng gói more_itertools .
import more_itertools
lst = range(1, 7)
for i, j in more_itertools.chunked(lst, 2):
print(f'{i} + {j} = {i+j}')
Tôi cần chia một danh sách cho một số và cố định như thế này.
l = [1,2,3,4,5,6]
def divideByN(data, n):
return [data[i*n : (i+1)*n] for i in range(len(data)//n)]
>>> print(divideByN(l,2))
[[1, 2], [3, 4], [5, 6]]
>>> print(divideByN(l,3))
[[1, 2, 3], [4, 5, 6]]
Có nhiều cách để làm điều đó. Ví dụ:
lst = [1,2,3,4,5,6]
[(lst[i], lst[i+1]) for i,_ in enumerate(lst[:-1])]
>>>[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
[i for i in zip(*[iter(lst)]*2)]
>>>[(1, 2), (3, 4), (5, 6)]
Tôi nghĩ rằng đây là một nơi tốt để chia sẻ khái quát của tôi về điều này cho n> 2, đây chỉ là một cửa sổ trượt trên một vòng lặp:
def sliding_window(iterable, n):
its = [ itertools.islice(iter, i, None)
for i, iter
in enumerate(itertools.tee(iterable, n)) ]
return itertools.izip(*its)
Sử dụng cách gõ để bạn có thể xác minh dữ liệu bằng công cụ phân tích tĩnh mypy :
from typing import Iterator, Any, Iterable, TypeVar, Tuple
T_ = TypeVar('T_')
Pairs_Iter = Iterator[Tuple[T_, T_]]
def legs(iterable: Iterator[T_]) -> Pairs_Iter:
begin = next(iterable)
for end in iterable:
yield begin, end
begin = end
Một cách tiếp cận đơn giản:
[(a[i],a[i+1]) for i in range(0,len(a),2)]
Điều này rất hữu ích nếu mảng của bạn là một và bạn muốn lặp lại theo từng cặp. Để lặp lại trên bộ ba hoặc nhiều hơn, chỉ cần thay đổi lệnh bước "phạm vi", ví dụ:
[(a[i],a[i+1],a[i+2]) for i in range(0,len(a),3)]
(bạn phải xử lý các giá trị vượt quá nếu độ dài mảng và bước không phù hợp)
Ở đây chúng ta có thể có alt_elem
phương thức có thể phù hợp với vòng lặp for của bạn.
def alt_elem(list, index=2):
for i, elem in enumerate(list, start=1):
if not i % index:
yield tuple(list[i-index:i])
a = range(10)
for index in [2, 3, 4]:
print("With index: {0}".format(index))
for i in alt_elem(a, index):
print(i)
Đầu ra:
With index: 2
(0, 1)
(2, 3)
(4, 5)
(6, 7)
(8, 9)
With index: 3
(0, 1, 2)
(3, 4, 5)
(6, 7, 8)
With index: 4
(0, 1, 2, 3)
(4, 5, 6, 7)
Lưu ý: Giải pháp trên có thể không hiệu quả khi xem xét các hoạt động được thực hiện trong func.
a_list = [1,2,3,4,5,6]
empty_list = []
for i in range(0,len(a_list),2):
empty_list.append(a_list[i]+a_list[i+1])
print(empty_list)