ฉันจะทำให้for
วนซ้ำหรือความเข้าใจในรายการเพื่อให้ทุกการวนซ้ำให้ฉันสององค์ประกอบ?
l = [1,2,3,4,5,6]
for i,k in ???:
print str(i), '+', str(k), '=', str(i+k)
เอาท์พุท:
1+2=3
3+4=7
5+6=11
ฉันจะทำให้for
วนซ้ำหรือความเข้าใจในรายการเพื่อให้ทุกการวนซ้ำให้ฉันสององค์ประกอบ?
l = [1,2,3,4,5,6]
for i,k in ???:
print str(i), '+', str(k), '=', str(i+k)
เอาท์พุท:
1+2=3
3+4=7
5+6=11
คำตอบ:
คุณต้องมีการติดตั้งpairwise()
(หรือgrouped()
)
สำหรับ 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)
หรือโดยทั่วไปแล้ว:
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)
ในหลาม 3 คุณสามารถแทนที่izip
ด้วยในตัวฟังก์ชั่นและวางzip()
import
เครดิตทั้งหมดให้กับมาร์ติโนสำหรับคำตอบของเขาที่จะคำถามของฉันฉันได้พบนี้จะมีประสิทธิภาพมากเป็นเพียง iterates มากกว่าหนึ่งครั้งรายการและไม่ได้สร้างรายการที่ไม่จำเป็นในกระบวนการ
หมายเหตุ : สิ่งนี้ไม่ควรสับสนกับpairwise
สูตรในitertools
เอกสารของ Python ซึ่งให้ผลs -> (s0, s1), (s1, s2), (s2, s3), ...
ตามที่@lazyrชี้ให้เห็นในความคิดเห็น
นอกจากนี้เล็กน้อยสำหรับผู้ที่ต้องการพิมพ์การตรวจสอบกับmypyใน 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
ฟังก์ชั่นสูตรอาหารที่มีชื่อเดียวกัน แน่นอนคุณจะเร็ว ...
izip_longest()
izip()
เช่น: ->list(izip_longest(*[iter([1, 2, 3])]*2, fillvalue=0))
[(1, 2), (3, 0)]
หวังว่านี่จะช่วยได้
ทีนี้คุณต้องมี tuple 2 องค์ประกอบดังนั้น
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)
ที่ไหน:
data[0::2]
หมายถึงการสร้างชุดย่อยขององค์ประกอบที่ (index % 2 == 0)
zip(x,y)
สร้างคอลเลกชัน tuple จาก x และ y คอลเลกชันองค์ประกอบดัชนีเดียวกันfor i, j, k in zip(data[0::3], data[1::3], data[2::3]):
import
ไม่ใช่หนึ่งในนั้น
>>> 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
ส่งคืนzip
วัตถุใน Python 3 ซึ่งไม่สามารถถอดได้ มันจะต้องถูกแปลงเป็นลำดับ ( list
, tuple
ฯลฯ ) ก่อน แต่"ไม่ทำงาน"นั้นค่อนข้างยืด
ทางออกที่ง่าย
l = [1, 2, 3, 4, 5, 6] สำหรับฉันอยู่ในช่วง (0, len (l), 2): พิมพ์ 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))
สำหรับเครื่องกำเนิดไฟฟ้าสามารถแก้ไขได้ง่ายสำหรับ tuples ที่ยาวขึ้น
ในขณะที่คำตอบทั้งหมดที่ใช้zip
นั้นถูกต้อง แต่ฉันพบว่าการใช้งานฟังก์ชั่นของคุณเองทำให้รหัสอ่านง่ายขึ้น
def pairwise(it):
it = iter(it)
while True:
try:
yield next(it), next(it)
except StopIteration:
# no more elements in the iterator
return
it = iter(it)
ส่วนหนึ่งเพื่อให้แน่ใจว่าit
เป็นจริง iterator, ไม่ได้เป็นเพียง iterable หากit
เป็นตัววนซ้ำแล้วบรรทัดนี้จะไม่มีตัวเลือก
การใช้งาน:
for a, b in pairwise([0, 1, 2, 3, 4, 5]):
print(a + b)
it
เป็นตัววนซ้ำเท่านั้นและไม่สามารถวนซ้ำได้ โซลูชันอื่น ๆ ดูเหมือนจะขึ้นอยู่กับความเป็นไปได้ในการสร้างตัววนซ้ำสองตัวสำหรับลำดับ
ฉันหวังว่านี่จะเป็นวิธีที่ยอดเยี่ยมกว่าในการทำเช่นนี้
a = [1,2,3,4,5,6]
zip(a[::2], a[1::2])
[(1, 2), (3, 4), (5, 6)]
ในกรณีที่คุณสนใจในประสิทธิภาพฉันได้สร้างเกณฑ์มาตรฐานขนาดเล็ก (ใช้ห้องสมุดของฉันsimple_benchmark
) เพื่อเปรียบเทียบประสิทธิภาพของโซลูชันและฉันได้รวมฟังก์ชันจากหนึ่งในแพ็คเกจของฉัน: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)
ดังนั้นหากคุณต้องการทางออกที่เร็วที่สุดโดยไม่มีการพึ่งพาจากภายนอกคุณก็ควรใช้วิธีการที่กำหนดโดย Johnysweb (ในขณะที่เขียนมันเป็นคำตอบที่ได้รับการยอมรับและยอมรับมากที่สุด)
หากคุณไม่ทราบพึ่งพาเพิ่มเติมแล้วgrouper
จากiteration_utilities
อาจจะบิตเร็วขึ้น
วิธีการบางอย่างมีข้อ จำกัด บางอย่างที่ไม่ได้กล่าวถึงในที่นี้
ตัวอย่างโซลูชันที่ใช้งานได้เฉพาะกับลำดับ (นั่นคือรายการสตริง ฯลฯ ) ตัวอย่างเช่นโซลูชัน Margus / pyanon / taskinoor ซึ่งใช้การจัดทำดัชนีในขณะที่โซลูชันอื่นทำงานบน iterable ใด ๆ (นั่นคือลำดับและตัวกำเนิด, ตัววนซ้ำ) เช่น Johnysweb / mic_e / โซลูชั่นของฉัน
Johnysweb ยังมีวิธีแก้ปัญหาที่ใช้งานได้กับขนาดอื่นที่ไม่ใช่ 2 ในขณะที่คำตอบอื่น ๆ ไม่ได้ (โอเคการiteration_utilities.grouper
ตั้งค่าจำนวนองค์ประกอบเป็น "กลุ่ม")
แล้วก็มีคำถามเกี่ยวกับสิ่งที่จะเกิดขึ้นหากมีองค์ประกอบจำนวนแปลก ๆ ในรายการ รายการที่เหลือควรจะถูกไล่ออก? รายการควรจะมีเบาะเพื่อให้ได้ขนาด? ควรคืนสินค้าที่เหลืออยู่เป็นรายการเดียวหรือไม่? คำตอบอื่น ๆ ไม่ได้อยู่ที่จุดนี้โดยตรง แต่ถ้าฉันไม่ได้มองข้ามสิ่งที่พวกเขาทำตามวิธีการที่รายการที่เหลือควรจะถูกไล่ออก (ยกเว้นคำตอบ taskinoors - ที่จริงจะยกข้อยกเว้น)
เมื่อgrouper
คุณสามารถตัดสินใจได้ว่าต้องการทำอะไร:
>>> 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)]
ใช้คำสั่งzip
และiter
ด้วยกัน:
ฉันพบว่าโซลูชันนี้ใช้งานiter
ได้ค่อนข้างหรูหรา:
it = iter(l)
list(zip(it, it))
# [(1, 2), (3, 4), (5, 6)]
ซึ่งผมพบในเอกสารซิปหลาม 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
ในการพูดคุยกับN
องค์ประกอบในแต่ละครั้ง:
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)
ส่งคืน tuple ด้วยอิลิเมนต์ถัดไปของแต่ละ iterable
l[::2]
ส่งกลับองค์ประกอบที่ 1, 3, 5 และอื่น ๆ ของรายการ: เครื่องหมายโคลอนแรกระบุว่าชิ้นเริ่มต้นที่จุดเริ่มต้นเนื่องจากไม่มีหมายเลขอยู่ด้านหลังเครื่องหมายโคลอนที่สองจำเป็นเฉพาะเมื่อคุณต้องการ 'ขั้นตอนในชิ้น '(ในกรณีนี้ 2)
l[1::2]
ทำสิ่งเดียวกัน แต่เริ่มต้นในองค์ประกอบที่สองของรายการดังนั้นจึงส่งกลับองค์ประกอบที่ 2, 4, 6, ฯลฯ ของรายการต้นฉบับ
[number::number]
ทำงานของไวยากรณ์ มีประโยชน์สำหรับผู้ที่ไม่ใช้งูใหญ่บ่อยครั้ง
ด้วยการเปิดออก:
l = [1,2,3,4,5,6]
while l:
i, k, *l = l
print(str(i), '+', str(k), '=', str(i+k))
สำหรับทุกคนที่อาจช่วยได้นี่คือวิธีแก้ปัญหาที่คล้ายกัน แต่มีคู่ที่ทับซ้อนกัน (แทนที่จะเป็นคู่ที่ไม่เกิดร่วมกัน)
จากเอกสารประกอบของ Python itertools :
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)
หรือโดยทั่วไปแล้ว:
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)
คุณสามารถใช้แพ็คเกจmore_itertools
import more_itertools
lst = range(1, 7)
for i, j in more_itertools.chunked(lst, 2):
print(f'{i} + {j} = {i+j}')
ฉันต้องการหารรายการด้วยตัวเลขและคงที่เช่นนี้
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]]
มีหลายวิธีที่จะทำเช่นนั้น ตัวอย่างเช่น:
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)]
คิดว่านี่เป็นสถานที่ที่ดีในการแบ่งปันภาพรวมของสิ่งนี้กับ n> 2 ซึ่งเป็นเพียงหน้าต่างบานเลื่อนเหนือ iterable:
def sliding_window(iterable, n):
its = [ itertools.islice(iter, i, None)
for i, iter
in enumerate(itertools.tee(iterable, n)) ]
return itertools.izip(*its)
ชื่อของคำถามนี้ทำให้เข้าใจผิดดูเหมือนว่าคุณกำลังมองหาคู่ที่ต่อเนื่องกัน แต่ถ้าคุณต้องการที่จะทำซ้ำในชุดของคู่ที่เป็นไปได้ทั้งหมดกว่านี้จะทำงาน:
for i,v in enumerate(items[:-1]):
for u in items[i+1:]:
การใช้การพิมพ์เพื่อให้คุณสามารถตรวจสอบข้อมูลโดยใช้เครื่องมือการวิเคราะห์แบบคงที่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
วิธีการง่าย ๆ :
[(a[i],a[i+1]) for i in range(0,len(a),2)]
สิ่งนี้มีประโยชน์หากอาร์เรย์ของคุณคือ a และคุณต้องการวนซ้ำโดยใช้คู่ หากต้องการทำซ้ำสามหรือมากกว่านั้นเพียงแค่เปลี่ยนคำสั่งขั้นตอน "range" ตัวอย่างเช่น:
[(a[i],a[i+1],a[i+2]) for i in range(0,len(a),3)]
(คุณต้องจัดการกับค่าส่วนเกินถ้าความยาวของอาเรย์และขั้นตอนไม่พอดี)
ที่นี่เราสามารถมีalt_elem
วิธีการที่เหมาะกับคุณสำหรับวง
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)
เอาท์พุท:
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)
หมายเหตุ: วิธีการแก้ปัญหาข้างต้นอาจไม่มีประสิทธิภาพในการพิจารณาดำเนินการใน 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)