Danh sách hiểu trên một danh sách lồng nhau?


219

Tôi có danh sách lồng nhau này:

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']]

Bây giờ, những gì tôi muốn làm là chuyển đổi từng thành phần trong danh sách để nổi. Giải pháp của tôi là thế này:

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

Nhưng điều này có thể được thực hiện bằng cách hiểu danh sách lồng nhau, phải không?

những gì tôi đã làm là:

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

Nhưng sau đó, kết quả là 100 giây với tổng số 2400.

bất kỳ giải pháp, một lời giải thích sẽ được nhiều đánh giá cao. Cảm ơn!


15
Bạn cũng muốn làm phẳng danh sách của bạn?
Greg Hewgill

@GregHewgill: OP đã không trả lời, nhưng dựa trên câu trả lời mà họ đã chấp nhận, có vẻ như họ muốn giữ nguyên tổ.
smci

Câu trả lời:


317

Đây là cách bạn sẽ làm điều này với một sự hiểu biết danh sách lồng nhau:

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

Điều này sẽ cung cấp cho bạn một danh sách các danh sách, tương tự như những gì bạn đã bắt đầu ngoại trừ với số float thay vì chuỗi. Nếu bạn muốn một danh sách phẳng thì bạn sẽ sử dụng [float(y) for x in l for y in x].


190

Dưới đây là cách chuyển đổi vòng lặp lồng nhau để hiểu danh sách lồng nhau:

nhập mô tả hình ảnh ở đây

Đây là cách hiểu danh sách lồng nhau hoạt động:

            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]

Đối với trường hợp của bạn, nó sẽ là một cái gì đó như thế này.

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

21
Siêu hữu ích! Làm rõ rằng các vòng lặp (từ trên xuống dưới) được sắp xếp từ trái sang phải trong trình tạo. Điều này không rõ ràng vì ở (f(x) for x in l)vị trí dòng thứ hai của vòng lặp for tương ứng ở bên trái.
dùng48956

Đây có vẻ là một lời giải thích thực sự gây ấn tượng với tôi, cảm ơn bạn!
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

Không chắc chắn đầu ra mong muốn của bạn là gì, nhưng nếu bạn đang sử dụng mức độ hiểu danh sách, thứ tự tuân theo thứ tự các vòng lặp lồng nhau, mà bạn có ngược lại. Vì vậy, tôi đã nhận được những gì tôi nghĩ bạn muốn với:

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

Nguyên tắc là: sử dụng cùng một thứ tự bạn sử dụng để viết nó ra như các vòng lặp lồng nhau.


đây sẽ là câu trả lời, vì đôi khi chúng ta không muốn đặt dấu ngoặc vuông cho iteratool
zinking

1
đây có thể không phải là câu trả lời chính xác vì nó đưa ra một danh sách không lồng nhau, nhưng đó là những gì tôi đang tìm kiếm, đặc biệt là nguyên tắc . Cảm ơn!
Rodrigo E. Principe

4

Vì tôi đến muộn một chút nhưng tôi muốn chia sẻ cách thực sự hiểu danh sách hoạt động đặc biệt là hiểu danh sách lồng nhau:

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

thực sự giống như:

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

Và bây giờ lồng ghép danh sách hiểu:

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

giống như;

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)

đầu ra:

[[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

Nếu bạn không thích cách hiểu danh sách lồng nhau, bạn cũng có thể sử dụng chức năng bản đồ ,

>>> 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]]

Mã của bạn tạo các đối tượng bản đồ thay vì danh sách: >>> 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>]] nhưng thêm một cuộc gọi bổ sung để liệt kê nó hoạt động như mong đợi: >>> float_l = [list(map(float, nested_list)) for nested_list in l]
pixelperinf 17/03/2017

@pixelperinf đó là do sự thay đổi ( thông tin sai ..) python3để trả lại các trình tạo ra khỏi sự hiểu biết.
javadba

3

Tôi đã có một vấn đề tương tự để giải quyết vì vậy tôi đã gặp câu hỏi này. Tôi đã làm một so sánh hiệu suất của câu trả lời của Andrew Clark và naraya mà tôi muốn chia sẻ.

Sự khác biệt chính giữa hai câu trả lời là cách chúng lặp đi lặp lại qua danh sách bên trong. Một trong số họ sử dụng bản đồ dựng sẵn , trong khi khác là sử dụng khả năng hiểu danh sách. Chức năng bản đồ có lợi thế hiệu suất nhẹ so với khả năng hiểu danh sách tương đương nếu nó không yêu cầu sử dụng lambdas . Vì vậy, trong bối cảnh của câu hỏi nàymap nên thực hiện tốt hơn một chút so với hiểu danh sách.

Hãy làm một tiêu chuẩn hiệu suất để xem nếu nó thực sự đúng. Tôi đã sử dụng python phiên bản 3.5.0 để thực hiện tất cả các thử nghiệm này. Trong bộ thử nghiệm đầu tiên, tôi muốn giữ các yếu tố trong mỗi danh sách là 10 và số lượng danh sách khác nhau từ 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

nhập mô tả hình ảnh ở đây

Trong các thử nghiệm tiếp theo, tôi muốn nâng số lượng phần tử trên mỗi danh sách lên 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

nhập mô tả hình ảnh ở đây

Hãy thực hiện một bước dũng cảm và sửa đổi số lượng phần tử trong danh sách thành 1000

>>> 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

nhập mô tả hình ảnh ở đây

Từ những thử nghiệm này, chúng tôi có thể kết luận rằng mapcó lợi ích về hiệu suất so với việc hiểu danh sách trong trường hợp này. Điều này cũng có thể áp dụng nếu bạn đang cố gắng chuyển sang một trong hai inthoặc str. Đối với số lượng nhỏ danh sách có ít thành phần trên mỗi danh sách, sự khác biệt là không đáng kể. Đối với các danh sách lớn hơn có nhiều yếu tố hơn trên mỗi danh sách, người ta có thể muốn sử dụng mapthay vì hiểu danh sách, nhưng nó hoàn toàn phụ thuộc vào nhu cầu ứng dụng.

Tuy nhiên, cá nhân tôi thấy việc hiểu danh sách trở nên dễ đọc và thành ngữ hơn map. Nó là một tiêu chuẩn thực tế trong trăn. Thông thường mọi người thành thạo và thoải mái hơn (đặc biệt là người mới bắt đầu) trong việc sử dụng hiểu danh sách hơn map.


2

Có, bạn có thể làm điều đó với một mã như vậy:

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

[float(y) for y in x for x in l]điều này sẽ dẫn đến một loạt 100
giây

2

Vấn đề này có thể được giải quyết mà không cần sử dụng cho vòng lặp. Mã dòng đơn sẽ đủ cho việc này. Sử dụng Nested Map với chức năng lambda cũng sẽ hoạt động ở đây.

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)

Và danh sách đầu ra sẽ như sau:

[[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
Do lambdas có bất kỳ lợi ích hiệu suất nào so với các giải pháp của @Andrew Clark hoặc Harry Binswanger (việc hiểu danh sách vanilla nhiều hơn)? Như lambdas có vẻ khó đọc hơn.
StefanJCollier

0

Theo tôi, cách tốt nhất để làm điều này là sử dụng itertoolsgói của python .

>>>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))

Điều này có thể đạt được bằng cách hiểu danh sách:

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

1
Điều này dường như không giải quyết câu hỏi trên đầu. Xin lưu ý rằng tất cả mọi thứ được đăng dưới dạng câu trả lời phải là một nỗ lực để trả lời câu hỏi mà nó được đăng lên.
Baum mit Augen

Mặc dù đoạn mã này có thể giải quyết câu hỏi, bao gồm một lời giải thích thực sự giúp cải thiện chất lượng bài đăng của bạn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai và những người đó có thể không biết lý do cho đề xuất mã của bạn. Xin vui lòng cố gắng không làm đông mã của bạn với các bình luận giải thích, điều này làm giảm khả năng đọc của cả mã và các giải thích!
Filnor 22/03/18

Được lồng cho vòng lặp bằng cách hiểu danh sách,
ADITYA KUMAR

1
Ok, rõ ràng, đây là một nỗ lực để trả lời câu hỏi. Tuy nhiên, điều này dường như là về một kịch bản hoàn toàn khác so với trong OP, bạn thậm chí không xử lý các danh sách lồng nhau làm đầu vào và ngay cả khi bạn thay đổi rằng đề xuất của bạn giống như những gì OP đã thử. Ngoài ra, tôi không thấy một ví dụ về thẻ giúp ích như thế nào khi câu hỏi về việc chuyển đổi chuỗi thành float.
Baum mit Augen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.