Trích xuất mục đầu tiên của mỗi danh sách phụ


146

Tôi đang tự hỏi đâu là cách tốt nhất để trích xuất mục đầu tiên của mỗi danh sách con trong danh sách các danh sách và nối nó vào danh sách mới. Vì vậy, nếu tôi có:

lst = [[a,b,c], [1,2,3], [x,y,z]]

và tôi muốn kéo ra a, 1xvà tạo một danh sách riêng biệt từ những.

Tôi đã thử:

lst2.append(x[0] for x in lst)

1
Mã của bạn là gần như chính xác. Vấn đề duy nhất là việc sử dụng hiểu danh sách.
Abhishek Găngal

Câu trả lời:


198

Sử dụng hiểu danh sách :

>>> lst = [['a','b','c'], [1,2,3], ['x','y','z']]
>>> lst2 = [item[0] for item in lst]
>>> lst2
['a', 1, 'x']

Phương pháp hiểu danh sách cũng nhanh nhất, thậm chí nhanh hơn phương pháp Numpy. Câu trả lời của jboi nói về so sánh hiệu suất,
Qiao Zhang

83

Bạn có thể sử dụng zip:

>>> lst=[[1,2,3],[11,12,13],[21,22,23]]
>>> zip(*lst)[0]
(1, 11, 21)

Hoặc, Python 3 zipkhông tạo danh sách:

>>> list(zip(*lst))[0]
(1, 11, 21)

Hoặc là,

>>> next(zip(*lst))
(1, 11, 21)

Hoặc, (yêu thích của tôi) sử dụng numpy:

>>> import numpy as np
>>> a=np.array([[1,2,3],[11,12,13],[21,22,23]])
>>> a
array([[ 1,  2,  3],
       [11, 12, 13],
       [21, 22, 23]])
>>> a[:,0]
array([ 1, 11, 21])

Chưa được đánh giá thấp nhưng đoạn mã đầu tiên (mã zip) tạo ra: đối tượng "'zip" không thể đăng ký được ". Python 3.6 trên Jupyter.
jboi

@jboi: Chỉ cần quấn listquanh nó trước hoặc sử dụng next. Cảm ơn
dawg

20

Có cùng một vấn đề và đã tò mò về hiệu suất của từng giải pháp.

Đây là %timeit:

import numpy as np
lst = [['a','b','c'], [1,2,3], ['x','y','z']]

Cách numpy đầu tiên, biến đổi mảng:

%timeit list(np.array(lst).T[0])
4.9 µs ± 163 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Hoàn toàn tự nhiên bằng cách sử dụng danh sách hiểu (như được giải thích bởi @alecxe):

%timeit [item[0] for item in lst]
379 ns ± 23.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Một cách khác bằng cách sử dụng zip(như được giải thích bởi @dawg):

%timeit list(zip(*lst))[0]
585 ns ± 7.26 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Cách thứ hai numpy. Cũng được giải thích bởi @dawg:

%timeit list(np.array(lst)[:,0])
4.95 µs ± 179 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Đáng ngạc nhiên (tốt, ít nhất là đối với tôi) cách bản địa sử dụng khả năng hiểu danh sách là nhanh nhất và nhanh hơn khoảng 10 lần so với cách thức gọn gàng. Chạy hai cách gọn gàng mà không có trận chung kết sẽ listtiết kiệm được khoảng một trận đấu mà vẫn chênh lệch gấp 10 lần.

Lưu ý rằng, khi tôi bao quanh mỗi đoạn mã với một lệnh gọi đến len, để đảm bảo rằng các Trình tạo chạy cho đến hết, thời gian vẫn giữ nguyên.


4
có một chi phí đáng kể khi tạo một mảng.
hpaulj

1
đồng ý với hpaulj, nếu bạn bắt đầu với mảng numpy, [:, 0] sẽ nhanh hơn. Hãy thử đi: lst = np.array ([['a', 'b', 'c'], [1,2,3], ['x', 'y', 'z']]), sau đó lst [:, 0]. Việc chuyển đổi trong các thử nghiệm thời gian ví dụ cho phép hiểu danh sách một lợi thế không công bằng. Vì vậy, nếu bạn có thể, hãy sử dụng một mảng gọn gàng để lưu trữ dữ liệu của bạn nếu tốc độ là mục tiêu cuối cùng của bạn. Numpy hầu như luôn luôn nhanh hơn. Nó được chế tạo cho tốc độ.
spainedustpi

13

Python bao gồm một hàm được gọi là itemgetter để trả về mục đó tại một chỉ mục cụ thể trong danh sách:

from operator import itemgetter

Truyền hàm itemgetter () chỉ mục của mục bạn muốn truy xuất. Để lấy mục đầu tiên, bạn sẽ sử dụng itemgetter (0). Điều quan trọng cần hiểu là itemgetter (0) tự trả về một hàm. Nếu bạn chuyển một danh sách cho chức năng đó, bạn sẽ nhận được mục cụ thể:

itemgetter(0)([10, 20, 30]) # Returns 10

Điều này hữu ích khi bạn kết hợp nó với map (), lấy một hàm làm đối số đầu tiên của nó và một danh sách (hoặc bất kỳ lần lặp nào khác) làm đối số thứ hai. Nó trả về kết quả của việc gọi hàm trên từng đối tượng trong iterable:

my_list = [['a', 'b', 'c'], [1, 2, 3], ['x', 'y', 'z']]
list(map(itemgetter(0), my_list)) # Returns ['a', 1, 'x']

Lưu ý rằng map () trả về một trình tạo, do đó kết quả được chuyển đến list () để có được danh sách thực tế. Tóm lại, nhiệm vụ của bạn có thể được thực hiện như thế này:

lst2.append(list(map(itemgetter(0), lst)))

Đây là một phương pháp thay thế cho việc sử dụng một sự hiểu biết danh sách, và phương pháp nào để lựa chọn phụ thuộc nhiều vào bối cảnh, khả năng đọc và sở thích.

Thông tin thêm: https://docs.python.org/3/l Library / operator.html # operator.itemgetter


2

Mã của bạn là gần như chính xác. Vấn đề duy nhất là việc sử dụng hiểu danh sách.

Nếu bạn sử dụng như: (x [0] cho x in lst), nó sẽ trả về một đối tượng trình tạo. Nếu bạn sử dụng như: [x [0] cho x in lst], nó sẽ trả về một danh sách.

Khi bạn nối đầu ra hiểu danh sách vào danh sách, đầu ra của mức độ hiểu danh sách là thành phần duy nhất của danh sách.

lst = [["a","b","c"], [1,2,3], ["x","y","z"]]
lst2 = []
lst2.append([x[0] for x in lst])
print lst2[0]

lst2 = [['a', 1, 'x']]

lst2 [0] = ['a', 1, 'x']

Xin vui lòng cho tôi biết nếu tôi không chính xác.


1
lst = [['a','b','c'], [1,2,3], ['x','y','z']]
outputlist = []
for values in lst:
    outputlist.append(values[0])

print(outputlist) 

Đầu ra: ['a', 1, 'x']


0

Bạn nói rằng bạn có một danh sách hiện có. Vì vậy, tôi sẽ đi với điều đó.

>>> lst1 = [['a','b','c'], [1,2,3], ['x','y','z']]
>>> lst2 = [1, 2, 3]

Ngay bây giờ bạn đang nối thêm đối tượng trình tạo vào danh sách thứ hai của bạn.

>>> lst2.append(item[0] for item in lst)
>>> lst2
[1, 2, 3, <generator object <genexpr> at 0xb74b3554>]

Nhưng bạn có thể muốn nó là một danh sách các mục đầu tiên

>>> lst2.append([item[0] for item in lst])
>>> lst2
[1, 2, 3, ['a', 1, 'x']]

Bây giờ chúng tôi nối thêm danh sách các mục đầu tiên vào danh sách hiện có. Nếu bạn muốn thêm các chủ đề vật phẩm, không phải danh sách của chúng, vào những cái hiện có, bạn sẽ sử dụng list.extend. Trong trường hợp đó, chúng tôi không phải lo lắng về việc thêm trình tạo, bởi vì phần mở rộng sẽ sử dụng trình tạo đó để thêm từng mục mà nó nhận được từ đó, để mở rộng danh sách hiện tại.

>>> lst2.extend(item[0] for item in lst)
>>> lst2
[1, 2, 3, 'a', 1, 'x']

hoặc là

>>> lst2 + [x[0] for x in lst]
[1, 2, 3, 'a', 1, 'x']
>>> lst2
[1, 2, 3]

https://docs.python.org/3.4/tutorial/datastructures.html#more-on-lists https://docs.python.org/3.4/tutorial/datastructures.html#list-comprehensions


1
Câu trả lời của bạn rất hay và đầy đủ cho những gì nghe có vẻ như OP muốn, nhưng tôi nghĩ từ appendtrong câu hỏi đang gây nhầm lẫn. Nghe có vẻ như anh ấy chỉ đơn giản muốn phần hiểu danh sách trong giải pháp của bạn.
beroe
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.