Làm thế nào để có được vị trí của mục trong danh sách?


169

Tôi đang lặp lại một danh sách và tôi muốn in ra chỉ mục của mặt hàng nếu nó đáp ứng một điều kiện nhất định. Làm thế nào tôi sẽ làm điều này?

Thí dụ:

testlist = [1,2,3,5,3,1,2,1,6]
for item in testlist:
    if item == 1:
        print position

Câu trả lời:


280

Hừm. Có một câu trả lời với sự hiểu biết danh sách ở đây, nhưng nó đã biến mất.

Đây:

 [i for i,x in enumerate(testlist) if x == 1]

Thí dụ:

>>> testlist
[1, 2, 3, 5, 3, 1, 2, 1, 6]
>>> [i for i,x in enumerate(testlist) if x == 1]
[0, 5, 7]

Cập nhật:

Được rồi, bạn muốn có một biểu thức trình tạo, chúng ta sẽ có một biểu thức trình tạo. Đây là danh sách hiểu một lần nữa, trong một vòng lặp for:

>>> for i in [i for i,x in enumerate(testlist) if x == 1]:
...     print i
... 
0
5
7

Bây giờ chúng tôi sẽ xây dựng một máy phát điện ...

>>> (i for i,x in enumerate(testlist) if x == 1)
<generator object at 0x6b508>
>>> for i in (i for i,x in enumerate(testlist) if x == 1):
...     print i
... 
0
5
7

và đủ nhanh chóng, chúng ta có thể gán nó cho một biến và sử dụng nó từ đó ...

>>> gen = (i for i,x in enumerate(testlist) if x == 1)
>>> for i in gen: print i
... 
0
5
7

Và để nghĩ rằng tôi đã từng viết FORTRAN.


6
Có lẽ sau 25 năm đặt câu hỏi về lập trình chức năng, tôi nghĩ cuối cùng tôi cũng đã có được manh mối. danh sách hiểu là da bom.
Charlie Martin

15
Tôi đoán bạn có nghĩa là "một chữ cái" và thẳng thắn, một tên dài hơn trong ví dụ này sẽ không có thêm nội dung thông tin.
Charlie Martin

2
Cảm ơn câu trả lời tuyệt vời. Tôi nghĩ rằng nhận xét của @ nailer có thể liên quan đến thực tế là bạn sử dụng 'i' trong hai bối cảnh khác nhau trong một dòng trong ví dụ về trình tạo; một bên trong sự hiểu biết, và bên kia để lặp qua nó. Tôi biết nó đã ném tôi đi trong một giây.
Brown

1
@CharlieMartin Bạn sử dụng 'i' cho chỉ mục thay vì mục theo một quy ước chung cho các biến ký tự đơn. Đặt tên cho chỉ mục 'chỉ mục' và mục 'mục' sẽ loại bỏ sự mơ hồ. Ngoài ra, bạn đang trả lời phụ huynh đã sử dụng 'mục' và 'vị trí' và đó là cách cư xử tốt để không đổi tên một cách không cần thiết của mã gốc trong câu trả lời của bạn.
mikemaccana

1
Siêu cú pháp: o) Bạn có thể dễ dàng nhận được một tham số dòng lệnh. Hãy để có một loạt các đối số : args = ['x', '-p1', 'v1', '-p2', 'v2']. Sau đó, lệnh args[[i for i, x in enumerate(args) if x == '-p1'][0] + 1]trở lại'v1'
Theodor Keinstein

170

Điều gì về sau đây?

print testlist.index(element)

Nếu bạn không chắc chắn liệu phần tử cần tìm có thực sự có trong danh sách hay không, bạn có thể thêm kiểm tra sơ bộ, như

if element in testlist:
    print testlist.index(element)

hoặc là

print(testlist.index(element) if element in testlist else None)

hoặc "cách pythonic", điều mà tôi không thích lắm vì mã không rõ ràng, nhưng đôi khi hiệu quả hơn,

try:
    print testlist.index(element)
except ValueError:
    pass

5
thay vì kiểm tra trước khi truy cập, bạn cũng có thể thử và kiểm traValueError
kratenko

Tôi nghĩ rằng anh ấy muốn tìm tất cả các lần xuất hiện, bạn dường như chỉ đưa ra lần đầu tiên.
tfv

@tfv Tôi không thấy làm thế nào bạn có thể đi đến kết luận như vậy vì câu hỏi nói "mục" chứ không phải "mục".
mmj

40

Sử dụng liệt kê:

testlist = [1,2,3,5,3,1,2,1,6]
for position, item in enumerate(testlist):
    if item == 1:
        print position

10
for i in xrange(len(testlist)):
  if testlist[i] == 1:
    print i

xrange thay vì phạm vi theo yêu cầu (xem bình luận).


thay thế phạm vi () bằng xrange () - phạm vi () tạo danh sách, xrange () tạo ra một trình vòng lặp. xrange () sử dụng bộ nhớ waaaay ít hơn và cuộc gọi đến nhanh hơn.
gnud

2
Tôi đồng ý cho các danh sách lớn trong chương trình python 2. Lưu ý rằng 'phạm vi' vẫn sẽ hoạt động trong python 3 (và hoạt động như xrange IIRC). 'xrange' đang đi theo con đường của khủng long.
jakber

2
Cập nhật: xrangebị mất trong Python 3.x, vì cái mới rangelà cũxrange
tim-oh

5

Đây là một cách khác để làm điều này:

try:
   id = testlist.index('1')
   print testlist[id]
except ValueError:
   print "Not Found"


2

Hãy thử dưới đây:

testlist = [1,2,3,5,3,1,2,1,6]    
position=0
for i in testlist:
   if i == 1:
      print(position)
   position=position+1

1

Nếu danh sách của bạn đủ lớn và bạn chỉ mong tìm thấy giá trị trong một số chỉ số thưa thớt, hãy xem xét rằng mã này có thể thực thi nhanh hơn nhiều vì bạn không phải lặp lại mọi giá trị trong danh sách.

lookingFor = 1
i = 0
index = 0
try:
  while i < len(testlist):
    index = testlist.index(lookingFor,i)
    i = index + 1
    print index
except ValueError: #testlist.index() cannot find lookingFor
  pass

Nếu bạn muốn tìm thấy giá trị rất nhiều, có lẽ bạn chỉ nên thêm "chỉ mục" vào danh sách và in danh sách ở cuối để tiết kiệm thời gian cho mỗi lần lặp.


Tôi đã làm một số bài kiểm tra thời gian. Kỹ thuật hiểu danh sách chạy nhanh hơn 38% so với mã này. (Tôi đã thay thế câu lệnh in của bạn bằng một danh sách đầu ra. Hãy gọi)
Deestan

Tôi cũng đã thực hiện một số thử nghiệm với kích thước danh sách 100000 giá trị ngẫu nhiên trong khoảng từ 1 đến 100. Mã tôi đã viết trong một số trường hợp nhanh gấp đôi. Không có thử nghiệm thời gian nào có thể so sánh với ứng dụng của người đăng (tất nhiên họ phải tự kiểm tra để chắc chắn). Tôi xin lỗi nếu ý kiến ​​của tôi gây bất lợi cho bài viết này.

0

Tôi nghĩ rằng có thể hữu ích khi sử dụng phương thức curselection () từ thư viện thte Tkinter:

from Tkinter import * 
listbox.curselection()

Phương pháp này hoạt động trên các tiện ích hộp danh sách Tkinter, vì vậy bạn sẽ cần xây dựng một trong số chúng thay vì danh sách.

Điều này sẽ trả về một vị trí như thế này:

('0',) (mặc dù các phiên bản sau của Tkinter có thể trả về danh sách các số nguyên thay thế)

Đó là cho vị trí đầu tiên và số lượng sẽ thay đổi theo vị trí mục.

Để biết thêm thông tin, xem trang này: http://effbot.org/tkinterbook/listbox.htm

Lời chào hỏi.


1
Ý tưởng thú vị. Vì điều này đòi hỏi phải nhập toàn bộ thư viện Tkinter, tuy nhiên, đây không phải là cách hiệu quả nhất để giải quyết vấn đề.
seaotternerd

3
Đây là một con đường không hiệu quả và uốn khúc đến nỗi tôi nói đó là một câu trả lời sai, ngay cả khi nó phần nào giải quyết được câu hỏi.

Câu trả lời này không liên quan gì đến câu hỏi.
Cody Piersall

0

Tại sao lại phức tạp hóa mọi thứ?

testlist = [1,2,3,5,3,1,2,1,6]
for position, item in enumerate(testlist):
    if item == 1:
        print position

0

Chỉ để minh họa ví dụ hoàn chỉnh cùng với input_listcái có searies1(ví dụ: input_list [0]) mà bạn muốn thực hiện tra cứu series2(ví dụ: input_list [1]) và lấy các chỉ mục của sê-ri 2 nếu nó tồn tại trong sê-ri1.

Lưu ý: Bạn certain conditionsẽ chuyển sang biểu thức lambda nếu điều kiện đơn giản

input_list = [[1,2,3,4,5,6,7],[1,3,7]]
series1 = input_list[0]
series2 = input_list[1]
idx_list = list(map(lambda item: series1.index(item) if item in series1 else None, series2))
print(idx_list)

đầu ra:

[0, 2, 6]

-2
testlist = [1,2,3,5,3,1,2,1,6]
for id, value in enumerate(testlist):
    if id == 1:
        print testlist[id]

Tôi đoán rằng đó là những gì bạn muốn. ;-) 'id' sẽ luôn là chỉ mục của các giá trị trong danh sách.

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.