Làm thế nào để trích xuất các phần tử thứ n từ một danh sách các bộ giá trị?


112

Tôi đang cố lấy phần tử thứ n từ danh sách các bộ giá trị.

Tôi có một cái gì đó như:

elements = [(1,1,1),(2,3,7),(3,5,10)]

Tôi chỉ muốn trích xuất các phần tử thứ hai của mỗi bộ vào một danh sách:

seconds = [1, 3, 5]

Tôi biết rằng nó có thể được thực hiện với một forvòng lặp nhưng tôi muốn biết liệu có cách nào khác không vì tôi có hàng nghìn bộ giá trị.

Câu trả lời:


185
n = 1 # N. . .
[x[n] for x in elements]

34

Điều này cũng hoạt động:

zip(*elements)[1]

(Tôi chủ yếu đăng bài này, để chứng minh với bản thân rằng tôi đã mò mẫm zip...)

Xem nó trong hành động:

>>> help(zip)

Trợ giúp về zip chức năng tích hợp trong nội trang mô-đun :

zip (...)

zip (seq1 [, seq2 [...]]) -> [(seq1 [0], seq2 [0] ...), (...)]

Trả về danh sách các bộ giá trị, trong đó mỗi bộ giá trị chứa phần tử thứ i từ mỗi chuỗi đối số. Danh sách trả về được cắt bớt độ dài bằng độ dài của chuỗi đối số ngắn nhất.

>>> elements = [(1,1,1),(2,3,7),(3,5,10)]
>>> zip(*elements)
[(1, 2, 3), (1, 3, 5), (1, 7, 10)]
>>> zip(*elements)[1]
(1, 3, 5)
>>>

Điều gọn gàng mà tôi đã học hôm nay: Sử dụng *listtrong các đối số để tạo danh sách tham số cho một hàm ...

Lưu ý : Trong Python3, ziptrả về một trình lặp, vì vậy thay vào đó, sử dụng list(zip(*elements))để trả về danh sách các bộ giá trị.


2
và sử dụng **dictđể tạo ra tranh cãi từ khóa: def test(foo=3, bar=3): return foo*barsau đód = {'bar': 9, 'foo'=12}; print test(**d)
Wayne Werner

@Wayne Werner: Đúng vậy. Công cụ này là tất cả những kiến thức chỉ thụ động (Tôi không thường xuyên sử dụng nó) - nhưng nó tốt để được nhắc nhở ngay bây giờ và sau đó để bạn biết nơi / những gì để tìm kiếm ...
Daren Thomas

1
Đúng câu chuyện - Tôi thấy rằng trong bất cứ điều gì tôi sử dụng thường xuyên đủ (Python, vim), tôi có xu hướng để nhắc nhở cần gọn gàng / mát tính năng mà tôi đã quên bởi vì tôi không sử dụng chúng thường xuyên.
Wayne Werner

cú pháp danh sách * khá hữu ích. bất kỳ ý tưởng nào về nơi điều này được mô tả trong tài liệu chính thức về python?
user1748155

Tôi chỉ tìm thấy nó trong hướng dẫn: docs.python.org/2/tutorial/...
Daren Thomas

30

Tôi biết rằng nó có thể được thực hiện với FOR nhưng tôi muốn biết nếu có cách khác

Có một cách khác. Bạn cũng có thể làm điều đó với mapitemgetter :

>>> from operator import itemgetter
>>> map(itemgetter(1), elements)

Tuy nhiên, điều này vẫn thực hiện một vòng lặp nội bộ và nó hơi chậm hơn so với việc hiểu danh sách:

setup = 'elements = [(1,1,1) for _ in range(100000)];from operator import itemgetter'
method1 = '[x[1] for x in elements]'
method2 = 'map(itemgetter(1), elements)'

import timeit
t = timeit.Timer(method1, setup)
print('Method 1: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup)
print('Method 2: ' + str(t.timeit(100)))

Các kết quả:

Phương pháp 1: 1.25699996948
Phương pháp 2: 1.46600008011

Nếu bạn cần lặp lại một danh sách thì sử dụng a forlà tốt.


2
Một bổ sung nhỏ: Trong python-3.x, điểm chuẩn sẽ hiển thị rằng bản đồ chỉ chiếm một phần của mili giây. Đó là bởi vì nó sẽ trả về một trình lặp. method2 = 'list (map (itemgetter (1), Elements))' kết xuất hành vi cũ.
Maik Beckmann

12

Tìm thấy điều này khi tôi đang tìm kiếm cách nhanh nhất để kéo phần tử thứ hai của danh sách 2 bộ. Không phải những gì tôi muốn nhưng đã chạy thử nghiệm tương tự như được hiển thị với phương pháp thứ 3 cộng với thử nghiệm phương pháp zip

setup = 'elements = [(1,1) for _ in range(100000)];from operator import itemgetter'
method1 = '[x[1] for x in elements]'
method2 = 'map(itemgetter(1), elements)'
method3 = 'dict(elements).values()'
method4 = 'zip(*elements)[1]'

import timeit
t = timeit.Timer(method1, setup)
print('Method 1: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup)
print('Method 2: ' + str(t.timeit(100)))
t = timeit.Timer(method3, setup)
print('Method 3: ' + str(t.timeit(100)))
t = timeit.Timer(method4, setup)
print('Method 4: ' + str(t.timeit(100)))

Method 1: 0.618785858154
Method 2: 0.711684942245
Method 3: 0.298138141632
Method 4: 1.32586884499

Vì vậy, nhanh hơn gấp đôi nếu bạn có một cặp 2 tuple để chỉ chuyển đổi thành một dict và lấy các giá trị.


Điều này có lẽ là hiển nhiên nhưng tôi sẽ đề cập đến dict(elements).values()sẽ dẫn đến một phần tử chính tả thay vì nén danh sách hoặc bản đồ. Đây chính xác là những gì tôi muốn (Tôi quan tâm đến các phần mềm bổ sung duy nhất) (+1 và cảm ơn bạn đã đăng bài) nhưng những người khác có thể thắc mắc tại sao dict nhanh hơn - nó không phân bổ bộ nhớ mà chỉ kiểm tra phần tử hiện có.
Greg0ry 21/12/16

6

Thời gian cho Python 3.6 để trích xuất phần tử thứ hai từ danh sách 2 bộ.

Ngoài ra, đã thêm numpyphương thức mảng, dễ đọc hơn (nhưng được cho là đơn giản hơn so với cách hiểu danh sách).

from operator import itemgetter
elements = [(1,1) for _ in range(100000)]

%timeit second = [x[1] for x in elements]
%timeit second = list(map(itemgetter(1), elements))
%timeit second = dict(elements).values()
%timeit second = list(zip(*elements))[1]
%timeit second = np.array(elements)[:,1]

và thời gian:

list comprehension:  4.73 ms ± 206 µs per loop
list(map):           5.3 ms ± 167 µs per loop
dict:                2.25 ms ± 103 µs per loop
list(zip)            5.2 ms ± 252 µs per loop
numpy array:        28.7 ms ± 1.88 ms per loop

Lưu ý rằng map()zip()không trả lại danh sách nữa, do đó chuyển đổi rõ ràng.



1

Sử dụng islicechain.from_iterable:

>>> from itertools import chain, islice
>>> elements = [(1,1,1),(2,3,7),(3,5,10)]
>>> list(chain.from_iterable(islice(item, 1, 2) for item in elements))
[1, 3, 5]

Điều này có thể hữu ích khi bạn cần nhiều hơn một phần tử:

>>> elements = [(0, 1, 2, 3, 4, 5), 
                (10, 11, 12, 13, 14, 15), 
                (20, 21, 22, 23, 24, 25)]
>>> list(chain.from_iterable(islice(tuple_, 2, 5) for tuple_ in elements))
[2, 3, 4, 12, 13, 14, 22, 23, 24]
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.