Hoàn toàn chọn các mục từ một danh sách hoặc tuple


120

Tôi có danh sách Python sau (cũng có thể là một tuple):

myList = ['foo', 'bar', 'baz', 'quux']

tôi có thể nói

>>> myList[0:3]
['foo', 'bar', 'baz']
>>> myList[::2]
['foo', 'baz']
>>> myList[1::2]
['bar', 'quux']

Làm thế nào để tôi chọn ra rõ ràng các mục mà chỉ số của chúng không có mẫu cụ thể? Ví dụ, tôi muốn chọn [0,2,3]. Hoặc từ một danh sách rất lớn gồm 1000 mặt hàng, tôi muốn chọn [87, 342, 217, 998, 500]. Có một số cú pháp Python làm điều đó? Một cái gì đó trông giống như:

>>> myBigList[87, 342, 217, 998, 500]

1
Điều này dường như là một bản sao. Các câu hỏi khác có nhiều phiếu hơn nhưng có vẻ như nó có câu trả lời tốt hơn với thời gian.
AnnanFay

Câu trả lời:


148
list( myBigList[i] for i in [87, 342, 217, 998, 500] )

Tôi đã so sánh các câu trả lời với python 2.5.2:

  • 19,7 usec: [ myBigList[i] for i in [87, 342, 217, 998, 500] ]

  • 20,6 usec: map(myBigList.__getitem__, (87, 342, 217, 998, 500))

  • 22,7 usec: itemgetter(87, 342, 217, 998, 500)(myBigList)

  • 24,6 usec: list( myBigList[i] for i in [87, 342, 217, 998, 500] )

Lưu ý rằng trong Python 3, 1st đã được thay đổi thành giống với 4th.


Một tùy chọn khác là bắt đầu với một numpy.arraycho phép lập chỉ mục thông qua một danh sách hoặc numpy.array:

>>> import numpy
>>> myBigList = numpy.array(range(1000))
>>> myBigList[(87, 342, 217, 998, 500)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: invalid index
>>> myBigList[[87, 342, 217, 998, 500]]
array([ 87, 342, 217, 998, 500])
>>> myBigList[numpy.array([87, 342, 217, 998, 500])]
array([ 87, 342, 217, 998, 500])

Các tuplekhông làm việc theo cách giống như đó là những lát.


2
Tốt nhất là một danh sách comp [myBigList[i] for i in [87, 342, 217, 998, 500]], nhưng tôi thích cách tiếp cận này tốt nhất.
zeekay

@MedhatHelmy Điều đó đã có trong câu trả lời. Tùy chọn thứ ba được sử dụng from operator import itemgettertrong phần khởi tạo của python -mtimeit.
Dan D.

Tôi tự hỏi, chỉ từ góc độ thiết kế ngôn ngữ, tại sao myBigList[(87, 342, 217, 998, 500)]không hoạt động khi myBigListlà một con trăn thường xuyên list? Khi tôi cố gắng mà tôi nhận được TypeError: list indices must be integers or slices, not tuple. Điều đó sẽ dễ dàng hơn nhiều so với việc đánh máy hiểu - có vấn đề liên quan đến thiết kế / triển khai ngôn ngữ không?
sparc_s Lan

@sparc_s Lan, điều này là do liststrong Python chỉ chấp nhận số nguyên hoặc lát. Truyền một số nguyên đảm bảo rằng chỉ có một mục được lấy từ danh sách hiện có. Truyền một lát cắt đảm bảo một phần của nó được truy xuất, nhưng chuyển một tuple giống như chuyển một kiểu dữ liệu ( tuple) làm đối số cho một kiểu dữ liệu ( list) khác về mặt cú pháp.
amanb

48

Cái này thì sao:

from operator import itemgetter
itemgetter(0,2,3)(myList)
('foo', 'baz', 'quux')

2
Đây là gợi cảm nhất cho đến nay. Yêu operatormô-đun đó !
jathanism

10

Nó không được tích hợp sẵn, nhưng bạn có thể tạo một lớp con của danh sách lấy các bộ dữ liệu làm "chỉ mục" nếu bạn muốn:

class MyList(list):

    def __getitem__(self, index):
        if isinstance(index, tuple):
            return [self[i] for i in index]
        return super(MyList, self).__getitem__(index)


seq = MyList("foo bar baaz quux mumble".split())
print seq[0]
print seq[2,4]
print seq[1::2]

in ấn

foo
['baaz', 'mumble']
['bar', 'quux']

2
(+1) Giải pháp gọn gàng! Với phần mở rộng này, việc xử lý các mảng trong Python bắt đầu trông giống R hoặc Matlab.
Assad Ebrahim

7

Có thể một sự hiểu biết danh sách theo thứ tự:

L = ['a', 'b', 'c', 'd', 'e', 'f']
print [ L[index] for index in [1,3,5] ]

Sản xuất:

['b', 'd', 'f']

Có phải đó là những gì bạn đang tìm kiếm?


6
>>> map(myList.__getitem__, (2,2,1,3))
('baz', 'baz', 'bar', 'quux')

Bạn cũng có thể tạo Listlớp riêng hỗ trợ các bộ dữ liệu làm đối số __getitem__nếu bạn muốn có thể thực hiện myList[(2,2,1,3)].


Trong khi điều này hoạt động thường không phải là một ý tưởng tốt để trực tiếp gọi các biến ma thuật. Bạn nên sử dụng một sự hiểu biết danh sách hoặc một mô-đun trợ giúp như thế nào operator.
jathanism

@jathanism: Tôi phải tôn trọng không đồng ý. Mặc dù nếu bạn lo lắng về khả năng tương thích về phía trước (trái ngược với công khai / riêng tư) tôi chắc chắn có thể thấy bạn đến từ đâu.
ninjagecko

Đó là nơi tôi đến. :) Theo đó, đó là lý do tương tự tại sao sử dụng tốt len(myList)hơn myList.__len__().
jathanism

một giải pháp sáng tạo. Tôi không nghĩ rằng đó là một ý tưởng tồi để gọi biến ma thuật. lập trình viên chọn cách ưa thích của họ dựa trên hoàn cảnh lập trình.
Jacob CUI

2

Tôi chỉ muốn chỉ ra, thậm chí cú pháp của itemgetter trông rất gọn gàng, nhưng nó hơi chậm khi thực hiện trên danh sách lớn.

import timeit
from operator import itemgetter
start=timeit.default_timer()
for i in range(1000000):
    itemgetter(0,2,3)(myList)
print ("Itemgetter took ", (timeit.default_timer()-start))

Mục đã lấy 1.065209062149279

start=timeit.default_timer()
for i in range(1000000):
    myList[0],myList[2],myList[3]
print ("Multiple slice took ", (timeit.default_timer()-start))

Nhiều lát lấy 0,6225321444745759


Đoạn đầu tiên, vui lòng thêm myList = np.array(range(1000000))nếu không bạn sẽ gặp lỗi.
Đám mây Cho

1

Một giải pháp khả thi khác:

sek=[]
L=[1,2,3,4,5,6,7,8,9,0]
for i in [2, 4, 7, 0, 3]:
   a=[L[i]]
   sek=sek+a
print (sek)

0

như thường khi bạn có một mảng nooly boolean như mask

[mylist[i] for i in np.arange(len(mask), dtype=int)[mask]]

Một lambda hoạt động cho bất kỳ chuỗi hoặc np.array:

subseq = lambda myseq, mask : [myseq[i] for i in np.arange(len(mask), dtype=int)[mask]]

newseq = subseq(myseq, mask)

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.