รายการความเข้าใจในรายการซ้อนกัน?


219

ฉันมีรายการซ้อนกันนี้:

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]

ทีนี้สิ่งที่ฉันอยากทำคือแปลงแต่ละองค์ประกอบในรายการให้ลอย ทางออกของฉันคือ:

newList = []
for x in l:
  for y in x:
    newList.append(float(y))

แต่สิ่งนี้สามารถทำได้โดยใช้ความเข้าใจในรายการซ้อนกันใช่มั้ย

สิ่งที่ฉันทำคือ:

[float(y) for y in x for x in l]

แต่ผลที่ได้คือพวงของ 100 กับผลรวมของ 2,400

ทางออกใด ๆ คำอธิบายจะได้รับการชื่นชมมาก ขอบคุณ!


15
คุณยังต้องการที่จะแผ่รายการของคุณ?
Greg Hewgill

@ GregHewgill: OP ไม่ตอบกลับ แต่ขึ้นอยู่กับคำตอบที่พวกเขายอมรับดูเหมือนว่าพวกเขาต้องการที่จะทำรังตามที่เป็นอยู่
smci

คำตอบ:


318

นี่คือวิธีที่คุณจะทำกับความเข้าใจในรายการแบบซ้อน:

[[float(y) for y in x] for x in l]

สิ่งนี้จะให้รายการของคุณคล้ายกับสิ่งที่คุณเริ่มด้วยยกเว้นด้วยลอยแทนสตริง [float(y) for x in l for y in x]หากคุณต้องการรายชื่อแบนหนึ่งแล้วคุณจะใช้


191

นี่คือวิธีการแปลงซ้อนสำหรับลูปเป็นรายการความเข้าใจซ้อน:

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือความเข้าใจของรายการซ้อนกัน:

            l a b c d e f
                  
In [1]: l = [ [ [ [ [ [ 1 ] ] ] ] ] ]
In [2]: for a in l:
   ...:     for b in a:
   ...:         for c in b:
   ...:             for d in c:
   ...:                 for e in d:
   ...:                     for f in e:
   ...:                         print(float(f))
   ...:                         
1.0

In [3]: [float(f)
         for a in l
   ...:     for b in a
   ...:         for c in b
   ...:             for d in c
   ...:                 for e in d
   ...:                     for f in e]
Out[3]: [1.0]

สำหรับกรณีของคุณมันจะเป็นแบบนี้

In [4]: new_list = [float(y) for x in l for y in x]

21
สุดยอดประโยชน์! ทำให้ชัดเจนว่ามีการสั่งวนรอบ (จากบนลงล่าง) จากซ้ายไปขวาในตัวสร้าง สิ่งนี้ไม่ชัดเจนตั้งแต่อยู่ใน(f(x) for x in l)ตำแหน่งที่บรรทัดที่สองของ for-loop ที่เท่ากันทางด้านซ้าย
user48956

นี่น่าจะเป็นคำอธิบายเดียวที่ทำให้ฉันกลับบ้านได้จริงๆขอบคุณ!
Douglas Plumley

48
>>> l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]
>>> new_list = [float(x) for xs in l for x in xs]
>>> new_list
[40.0, 20.0, 10.0, 30.0, 20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0, 30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]

42

ไม่แน่ใจว่าผลลัพธ์ที่คุณต้องการคืออะไร แต่ถ้าคุณใช้ความเข้าใจในรายการคำสั่งจะเรียงตามลำดับของลูปซ้อนกันซึ่งคุณมีย้อนหลัง ดังนั้นฉันจึงได้สิ่งที่ฉันต้องการ:

[float(y) for x in l for y in x]

หลักการคือ: ใช้คำสั่งเดียวกับที่คุณใช้ในการเขียนออกมาเป็นแบบซ้อนสำหรับลูป


นี่ควรเป็นคำตอบเนื่องจากบางครั้งเราไม่ต้องการให้วงเล็บ iteratool
zinking

1
นี้อาจจะไม่ใช่คำตอบที่ถูกต้องมันจะออกผลลัพธ์รายการซ้อนกันไม่ใช่ แต่มันเป็นสิ่งที่ผมกำลังมองหาเฉพาะหลักการ ขอบคุณ!
Rodrigo E. Principe

4

ตั้งแต่ฉันมาสายนิดหน่อย แต่ฉันอยากจะแบ่งปันว่ารายการความเข้าใจนั้นทำงานได้อย่างไรโดยเฉพาะอย่างยิ่งรายการที่ซ้อนกัน:

New_list= [[float(y) for x in l]

เป็นเช่นเดียวกับ:

New_list=[]
for x in l:
    New_list.append(x)

และความเข้าใจในรายการซ้อนตอนนี้:

[[float(y) for y in x] for x in l]

เป็นเช่นเดียวกับ;

new_list=[]
for x in l:
    sub_list=[]
    for y in x:
        sub_list.append(float(y))

    new_list.append(sub_list)

print(new_list)

เอาท์พุท:

[[40.0, 20.0, 10.0, 30.0], [20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], [30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]]

3

หากคุณไม่ชอบความเข้าใจในรายการแบบซ้อนคุณสามารถใช้ฟังก์ชันแผนที่ได้เช่นกัน

>>> from pprint import pprint

>>> l = l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']] 

>>> pprint(l)
[['40', '20', '10', '30'],
['20', '20', '20', '20', '20', '30', '20'],
['30', '20', '30', '50', '10', '30', '20', '20', '20'],
['100', '100'],
['100', '100', '100', '100', '100'],
['100', '100', '100', '100']]

>>> float_l = [map(float, nested_list) for nested_list in l]

>>> pprint(float_l)
[[40.0, 20.0, 10.0, 30.0],
[20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0],
[30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0],
[100.0, 100.0],
[100.0, 100.0, 100.0, 100.0, 100.0],
[100.0, 100.0, 100.0, 100.0]]

รหัสของคุณสร้างวัตถุแผนที่แทนรายการ: >>> float_l = [map(float, nested_list) for nested_list in l] [[<map at 0x47be9b0>], [<map at 0x47be2e8>], [<map at 0x47be4a8>], [<map at 0x47beeb8>], [<map at 0x484b048>], [<map at 0x484b0b8>]] แต่เพิ่มการโทรเพิ่มเติมเพื่อแสดงรายการให้ทำงานตามที่คาดไว้: >>> float_l = [list(map(float, nested_list)) for nested_list in l]
pixelperfect

@ พิกเซลที่สมบูรณ์แบบที่เกิดจากการเปลี่ยนแปลง ( misinformed .. ) ในpython3การส่งคืนกำเนิดจากความเข้าใจ
javadba

3

ฉันมีปัญหาคล้ายกันในการแก้ปัญหาดังนั้นฉันจึงเจอคำถามนี้ ฉันทำการเปรียบเทียบประสิทธิภาพของคำตอบของ Andrew Clark และ narayan ซึ่งฉันต้องการแบ่งปัน

ความแตกต่างหลักระหว่างสองคำตอบคือวิธีที่พวกเขาทำซ้ำในรายการภายใน หนึ่งในนั้นใช้แผนที่ builtin ในขณะที่อื่น ๆ ใช้ list comprehension ฟังก์ชั่นแผนที่มีความได้เปรียบเล็กน้อยเพื่อประสิทธิภาพการทำงานที่เข้าใจรายการเทียบเท่าถ้ามันไม่จำเป็นต้อง lambdas ดังนั้นในบริบทของคำถามนี้mapควรทำงานได้ดีกว่าความเข้าใจในรายการเล็กน้อย

ให้ทำเกณฑ์ประสิทธิภาพเพื่อดูว่าจริงหรือไม่ ฉันใช้ python เวอร์ชั่น 3.5.0 เพื่อทำการทดสอบทั้งหมดนี้ ในชุดทดสอบครั้งแรกฉันต้องการเก็บองค์ประกอบต่อรายการเป็น10และเปลี่ยนจำนวนรายการจาก10-100,000

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10]"
>>> 100000 loops, best of 3: 15.2 usec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10]"
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100]"
>>> 100000 loops, best of 3: 15.2 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100]"
>>> 10000 loops, best of 3: 19.6 usec per loop 

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*1000]"
>>> 1000 loops, best of 3: 1.43 msec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*1000]"
>>> 100 loops, best of 3: 1.91 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*10000]"
>>> 100 loops, best of 3: 13.6 msec per loop   
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*10000]"
>>> 10 loops, best of 3: 19.1 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,10))]*100000]"
>>> 10 loops, best of 3: 164 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,10))]*100000]"
>>> 10 loops, best of 3: 216 msec per loop

ป้อนคำอธิบายรูปภาพที่นี่

ในชุดต่อไปของการทดสอบผมอยากจะเพิ่มจำนวนขององค์ประกอบต่อรายการเพื่อ100

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10]"
>>> 10000 loops, best of 3: 110 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10]"
>>> 10000 loops, best of 3: 151 usec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100]"
>>> 1000 loops, best of 3: 1.11 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100]"
>>> 1000 loops, best of 3: 1.5 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*1000]"
>>> 100 loops, best of 3: 11.2 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*1000]"
>>> 100 loops, best of 3: 16.7 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*10000]"
>>> 10 loops, best of 3: 134 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*10000]"
>>> 10 loops, best of 3: 171 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,100))]*100000]"
>>> 10 loops, best of 3: 1.32 sec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,100))]*100000]"
>>> 10 loops, best of 3: 1.7 sec per loop

ป้อนคำอธิบายรูปภาพที่นี่

ให้ใช้ขั้นตอนที่กล้าหาญและแก้ไขจำนวนองค์ประกอบในรายการเป็น1,000

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10]"
>>> 1000 loops, best of 3: 800 usec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10]"
>>> 1000 loops, best of 3: 1.16 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100]"
>>> 100 loops, best of 3: 8.26 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100]"
>>> 100 loops, best of 3: 11.7 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*1000]"
>>> 10 loops, best of 3: 83.8 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*1000]"
>>> 10 loops, best of 3: 118 msec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*10000]"
>>> 10 loops, best of 3: 868 msec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*10000]"
>>> 10 loops, best of 3: 1.23 sec per loop

>>> python -m timeit "[list(map(float,k)) for k in [list(range(0,1000))]*100000]"
>>> 10 loops, best of 3: 9.2 sec per loop
>>> python -m timeit "[[float(y) for y in x] for x in [list(range(0,1000))]*100000]"
>>> 10 loops, best of 3: 12.7 sec per loop

ป้อนคำอธิบายรูปภาพที่นี่

จากการทดสอบเหล่านี้เราสามารถสรุปได้ว่าmapมีประโยชน์ด้านประสิทธิภาพมากกว่ารายการความเข้าใจในกรณีนี้ นอกจากนี้ยังมีผลบังคับใช้ถ้าคุณกำลังพยายามที่จะโยนอย่างใดอย่างหนึ่งหรือint strสำหรับรายการจำนวนน้อยที่มีองค์ประกอบน้อยกว่าต่อรายการความแตกต่างนั้นเล็กน้อย สำหรับรายการขนาดใหญ่ที่มีองค์ประกอบมากขึ้นต่อรายการหนึ่งอาจต้องการใช้mapแทนรายการเข้าใจ แต่ทั้งหมดขึ้นอยู่กับความต้องการของแอปพลิเคชัน

mapแต่ผมเองพบความเข้าใจในรายชื่อที่จะอ่านได้มากขึ้นและสำนวนกว่า เป็นมาตรฐานจริงในหลาม คนมักจะมีความเชี่ยวชาญมากขึ้นและสะดวกสบาย (พิเศษเริ่มต้น) mapในการใช้ความเข้าใจรายการกว่า


2

ใช่คุณสามารถทำได้ด้วยรหัสดังกล่าว:

l = [[float(y) for y in x] for x in l]

[float(y) for y in x for x in l]สิ่งนี้จะส่งผลให้กลุ่มของ 100 กับผลรวมของ
2,400

2

ปัญหานี้สามารถแก้ไขได้โดยไม่ต้องใช้ลูปรหัสบรรทัดเดียวจะเพียงพอสำหรับการนี้ การใช้แผนที่แบบซ้อนกับฟังก์ชั่นแลมบ์ดาจะทำงานได้ที่นี่เช่นกัน

l = [['40', '20', '10', '30'], ['20', '20', '20', '20', '20', '30', '20'], ['30', '20', '30', '50', '10', '30', '20', '20', '20'], ['100', '100'], ['100', '100', '100', '100', '100'], ['100', '100', '100', '100']]

map(lambda x:map(lambda y:float(y),x),l)

และรายการผลลัพธ์จะเป็นดังนี้:

[[40.0, 20.0, 10.0, 30.0], [20.0, 20.0, 20.0, 20.0, 20.0, 30.0, 20.0], [30.0, 20.0, 30.0, 50.0, 10.0, 30.0, 20.0, 20.0, 20.0], [100.0, 100.0], [100.0, 100.0, 100.0, 100.0, 100.0], [100.0, 100.0, 100.0, 100.0]]

1
แลมบ์ดามีประโยชน์ด้านการแสดงมากกว่าพูดว่า @Andrew Clark หรือโซลูชั่นของ Harry Binswanger (ยิ่งเข้าใจวานิลลามากขึ้น)? ในขณะที่แลมบ์ดาดูเหมือนอ่านยากขึ้น
StefanJCollier

0

วิธีที่ดีที่สุดในการทำเช่นนี้ในความคิดของฉันคือการใช้itertoolsแพคเกจของงูใหญ่

>>>import itertools
>>>l1 = [1,2,3]
>>>l2 = [10,20,30]
>>>[l*2 for l in itertools.chain(*[l1,l2])]
[2, 4, 6, 20, 40, 60]


-2
    deck = [] 
    for rank in ranks:
        for suit in suits:
            deck.append(('%s%s')%(rank, suit))

สิ่งนี้สามารถทำได้โดยการใช้ list comprehension:

[deck.append((rank,suit)) for suit in suits for rank in ranks ]

1
สิ่งนี้ไม่ได้ตอบคำถามอยู่ด้านบนเลย โปรดทราบว่าทุกสิ่งที่โพสต์เป็นคำตอบต้องพยายามตอบคำถามที่โพสต์ไว้
Baum mit Augen

ในขณะที่ข้อมูลโค้ดนี้อาจแก้ไขคำถามรวมถึงคำอธิบายช่วยปรับปรุงคุณภาพของโพสต์ของคุณ จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตและคนเหล่านั้นอาจไม่ทราบสาเหตุของการแนะนำรหัสของคุณ โปรดอย่าพยายามทำให้รหัสของคุณแน่นเกินไปด้วยคำอธิบายที่อธิบายซึ่งจะช่วยลดความสามารถในการอ่านของทั้งรหัสและคำอธิบาย!
Filnor

ซ้อนสำหรับลูปโดยใช้ list comprehension
ADITYA KUMAR

1
ตกลงเห็นได้ชัดว่านี่เป็นความพยายามที่จะตอบคำถาม อย่างไรก็ตามสิ่งนี้ดูเหมือนจะเป็นสถานการณ์ที่แตกต่างอย่างสิ้นเชิงกว่าใน OP คุณไม่ได้จัดการกับรายการที่ซ้อนกันเป็นอินพุตและแม้ว่าคุณจะเปลี่ยนคำแนะนำของคุณนั้นเป็นสิ่งที่ OP พยายามทำอยู่แล้ว นอกจากนี้ฉันไม่เห็นตัวอย่างเกี่ยวกับการ์ดช่วยเมื่อคำถามเกี่ยวกับการแปลงสตริงให้ลอย
Baum mit Augen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.