Truy cập chỉ mục trong các vòng lặp 'cho'?


3605

Làm thế nào để tôi truy cập vào chỉ mục trong một forvòng lặp như sau?

ints = [8, 23, 45, 12, 78]
for i in ints:
    print('item #{} = {}'.format(???, i))

Tôi muốn có được đầu ra này:

item #1 = 8
item #2 = 23
item #3 = 45
item #4 = 12
item #5 = 78

Khi tôi lặp qua nó bằng một forvòng lặp, làm thế nào để tôi truy cập vào chỉ mục vòng lặp, từ 1 đến 5 trong trường hợp này?


42
Lưu ý rằng các chỉ mục trong python bắt đầu từ 0, vì vậy các chỉ mục cho danh sách ví dụ của bạn là 0 đến 4 chứ không phải 1 đến 5
plugwash

Câu trả lời:


6116

Sử dụng một biến trạng thái bổ sung, chẳng hạn như biến chỉ mục (mà bạn thường sử dụng trong các ngôn ngữ như C hoặc PHP), được coi là không pythonic.

Tùy chọn tốt hơn là sử dụng hàm dựng enumerate()sẵn, có sẵn trong cả Python 2 và 3:

for idx, val in enumerate(ints):
    print(idx, val)

Kiểm tra PEP 279 để biết thêm.


61
Như Aaron chỉ ra bên dưới, hãy sử dụng start = 1 nếu bạn muốn nhận 1-5 thay vì 0-4.
clozach

2
Không enumeratephát sinh chi phí khác?
TheRealChx101

@ TheRealChx101 theo các thử nghiệm của tôi (Python 3.6.3), sự khác biệt là không đáng kể và đôi khi thậm chí có lợi cho enumerate.
Błotosmętek

804

Sử dụng vòng lặp for, làm cách nào để truy cập chỉ mục vòng lặp, từ 1 đến 5 trong trường hợp này?

Sử dụng enumerateđể lấy chỉ mục với phần tử khi bạn lặp:

for index, item in enumerate(items):
    print(index, item)

Và lưu ý rằng các chỉ mục của Python bắt đầu từ 0, vì vậy bạn sẽ nhận được 0 đến 4 với các chỉ số trên. Nếu bạn muốn đếm, 1 đến 5, hãy làm điều này:

for count, item in enumerate(items, start=1):
    print(count, item)

Dòng điều khiển không độc

Những gì bạn đang yêu cầu là tương đương với Pythonic, đây là thuật toán mà hầu hết các lập trình viên của các ngôn ngữ cấp thấp hơn sẽ sử dụng:

index = 0            # Python's indexing starts at zero
for item in items:   # Python's for loops are a "for each" loop 
    print(index, item)
    index += 1

Hoặc trong các ngôn ngữ không có vòng lặp for-every:

index = 0
while index < len(items):
    print(index, items[index])
    index += 1

hoặc đôi khi phổ biến hơn (nhưng không phổ biến) được tìm thấy trong Python:

for index in range(len(items)):
    print(index, items[index])

Sử dụng hàm liệt kê

enumerateHàm của Python làm giảm sự lộn xộn thị giác bằng cách ẩn kế toán cho các chỉ mục và đóng gói iterable vào một iterable khác (một enumerateđối tượng) mang lại một tuple hai mục của chỉ mục và mục mà lần lặp ban đầu sẽ cung cấp. Trông như thế này:

for index, item in enumerate(items, start=0):   # default is zero
    print(index, item)

Mẫu mã này là khá đầy đủ các kinh điển ví dụ hình về sự khác biệt giữa mã là thành ngữ của Python và mã không phải là mã. Mã thành ngữ là Python tinh vi (nhưng không phức tạp), được viết theo cách mà nó được dự định sử dụng. Mã thành ngữ được các nhà thiết kế ngôn ngữ mong đợi, điều đó có nghĩa là thông thường mã này không chỉ dễ đọc hơn mà còn hiệu quả hơn.

Đếm

Ngay cả khi bạn không cần chỉ mục khi bạn đi, nhưng bạn cần một số lần lặp (đôi khi mong muốn) bạn có thể bắt đầu 1và số cuối cùng sẽ là số của bạn.

for count, item in enumerate(items, start=1):   # default is zero
    print(item)

print('there were {0} items printed'.format(count))

Số lượng dường như nhiều hơn những gì bạn định yêu cầu (trái ngược với chỉ số) khi bạn nói bạn muốn từ 1 đến 5.


Phá vỡ nó - một lời giải thích từng bước

Để phá vỡ các ví dụ này, giả sử chúng tôi có một danh sách các mục mà chúng tôi muốn lặp lại với một chỉ mục:

items = ['a', 'b', 'c', 'd', 'e']

Bây giờ chúng ta chuyển cái lặp này để liệt kê, tạo ra một đối tượng liệt kê:

enumerate_object = enumerate(items) # the enumerate object

Chúng ta có thể kéo mục đầu tiên ra khỏi vòng lặp này mà chúng ta sẽ nhận được trong một vòng lặp với nextchức năng:

iteration = next(enumerate_object) # first iteration from enumerate
print(iteration)

Và chúng ta thấy chúng ta nhận được một tuple 0, chỉ mục đầu tiên và 'a', mục đầu tiên:

(0, 'a')

chúng ta có thể sử dụng cái được gọi là " giải nén chuỗi " để trích xuất các phần tử từ bộ hai này:

index, item = iteration
#   0,  'a' = (0, 'a') # essentially this.

và khi chúng tôi kiểm tra index, chúng tôi thấy nó đề cập đến chỉ số đầu tiên, 0 và itemđề cập đến mục đầu tiên , 'a'.

>>> print(index)
0
>>> print(item)
a

Phần kết luận

  • Các chỉ mục Python bắt đầu từ 0
  • Để có được các chỉ mục này từ một lần lặp khi bạn lặp lại nó, hãy sử dụng hàm liệt kê
  • Sử dụng phép liệt kê theo cách thành ngữ (cùng với bộ giải nén tuple) tạo ra mã dễ đọc và dễ bảo trì hơn:

Vì vậy, làm điều này:

for index, item in enumerate(items, start=0):   # Python indexes start at zero
    print(index, item)

1
Ví dụ " Lấy số đếm " có hoạt động khi itemstrống không?
Bergi

Tôi đang gửi dữ liệu bằng cách sử dụng ajax tới Django dưới dạng một mảng dưới dạng hai giá trị trong một legData biến với các giá trị là [1406, 1409]. Nếu tôi in ra bàn điều khiển bằng cách sử dụng print(legData), đầu ra là [1406,1409] . Tuy nhiên, nếu tôi cố phân tích các giá trị riêng lẻ của danh sách như thế for idx, xLeg in enumerate(legData): print(idx, xLeg), nó sẽ cho tôi một đầu ra của các số nguyên riêng lẻ như [, 1, 4, 0, 6, v.v. so với các chỉ số 0, 1, 2, 3, 4, 4 v.v. (vâng, dấu ngoặc vuông & dấu phẩy cũng đang được xuất ra như thể chúng là một phần của chính dữ liệu ). Điều gì đang xảy ra ở đây?
dùng12379095

@ user12379095 bạn có thể có dữ liệu sai loại (một chuỗi) và bạn cần chuyển đổi nó thành một danh sách số thực tế thay vì một chuỗi. Đó là một phần ngoài chủ đề ở đây, xin vui lòng xóa bình luận của bạn và gắn cờ của tôi sẽ bị xóa vì không còn cần thiết khi bạn thấy điều này.
Aaron Hall

152

Nó khá đơn giản để bắt đầu nó từ 1khác 0:

for index, item in enumerate(iterable, start=1):
   print index, item

Ghi chú

Gợi ý quan trọng, mặc dù một chút sai lệch vì indexsẽ là một tuple (idx, item)ở đây. Tốt để đi.


11
Câu hỏi là về chỉ số danh sách; vì chúng bắt đầu từ 0 nên có rất ít điểm bắt đầu từ số khác vì các chỉ số sẽ sai (vâng, OP cũng nói sai trong câu hỏi). Mặt khác, việc gọi biến là tuple của index, itemjust indexlà rất sai lệch, như bạn đã lưu ý. Chỉ cần sử dụng for index, item in enumerate(ints).
Antti Haapala

1
Tốt hơn là đặt chỉ mục bên trong các cặp dấu ngoặc đơn là (chỉ mục), nó sẽ hoạt động trên cả hai phiên bản Python 2 và 3.
hygull

1
@AnttiHaapala Lý do, tôi cho rằng, đó là đầu ra dự kiến ​​của câu hỏi bắt đầu từ chỉ số 1 thay vì 0
Pushkin

90
for i in range(len(ints)):
   print i, ints[i]

10
Điều đó có lẽ nên xrangedành cho trước 3.0.
Ben Trống

43
Sử dụng phép liệt kê thay thế
saulspatz

3
Đối với Python 2.3 ở trên, hãy sử dụng hàm tích hợp liệt kê vì nó có nhiều Pythonic hơn.
januarvs

Enum Cả không phải lúc nào cũng tốt hơn - nó phụ thuộc vào yêu cầu của ứng dụng. Trong tình huống hiện tại của tôi, các mối quan hệ giữa độ dài đối tượng có ý nghĩa đối với ứng dụng của tôi. Mặc dù tôi đã bắt đầu sử dụng phép liệt kê, tôi đã chuyển sang cách tiếp cận này để tránh phải viết logic để chọn đối tượng cần liệt kê.
adg

1
@adg Tôi không thấy làm thế nào để tránh enumeratelưu bất kỳ logic nào; bạn vẫn phải chọn đối tượng nào để lập chỉ mục i, phải không?
chepner

47

Theo tiêu chuẩn trong Python, có một số cách để làm điều này. Trong tất cả các ví dụ giả định:lst = [1, 2, 3, 4, 5]

1. Sử dụng liệt kê ( được coi là thành ngữ nhất )

for index, element in enumerate(lst):
    # do the things that need doing here

Đây cũng là lựa chọn an toàn nhất theo ý kiến ​​của tôi vì cơ hội đi vào đệ quy vô hạn đã bị loại bỏ. Cả mục và chỉ mục của nó được giữ trong các biến và không cần phải viết thêm bất kỳ mã nào để truy cập vào mục.

2. Tạo một biến để giữ chỉ mục ( sử dụngfor )

for index in range(len(lst)):   # or xrange
    # you will have to write extra code to get the element

3. Tạo một biến để giữ chỉ mục ( sử dụngwhile )

index = 0
while index < len(lst):
    # you will have to write extra code to get the element
    index += 1  # escape infinite recursion

4. Luôn có một cách khác

Như đã giải thích trước đây, có những cách khác để làm điều này chưa được giải thích ở đây và chúng thậm chí có thể áp dụng nhiều hơn trong các tình huống khác. ví dụ như sử dụng itertools.chainvới cho. Nó xử lý các vòng lặp lồng nhau tốt hơn so với các ví dụ khác.


30

Cách thức cũ:

for ix in range(len(ints)):
    print ints[ix]

Danh sách hiểu

[ (ix, ints[ix]) for ix in range(len(ints))]

>>> ints
[1, 2, 3, 4, 5]
>>> for ix in range(len(ints)): print ints[ix]
... 
1
2
3
4
5
>>> [ (ix, ints[ix]) for ix in range(len(ints))]
[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]
>>> lc = [ (ix, ints[ix]) for ix in range(len(ints))]
>>> for tup in lc:
...     print tup
... 
(0, 1)
(1, 2)
(2, 3)
(3, 4)
(4, 5)
>>> 

3
Điều này không sai và được sử dụng trong C / C ++ và những người khác. Nó được coi là không pythonic, nhưng cũng có thể được sử dụng trong python. Giống như các giải pháp đơn giản, chia nó thành nguồn: +
Valor Naram

Một số người cực đoan trăn sẽ nói, đừng làm điều này. Nhưng tôi đã nói nó chỉ để chỉ ra rằng có nhiều hơn một cách có thể
Valor Naram

21

Cách nhanh nhất để truy cập các chỉ mục của danh sách trong vòng lặp trong Python 2.7 là sử dụng phương thức phạm vi cho danh sách nhỏ và phương pháp liệt kê cho danh sách kích thước trung bình và khổng lồ.

Vui lòng xem các cách tiếp cận khác nhau có thể được sử dụng để lặp qua danh sách và truy cập giá trị chỉ mục và số liệu hiệu suất của chúng (mà tôi cho là sẽ hữu ích cho bạn) trong các mẫu mã dưới đây:

from timeit import timeit

# Using range
def range_loop(iterable):
    for i in range(len(iterable)):
        1 + iterable[i]

# Using xrange
def xrange_loop(iterable):
    for i in xrange(len(iterable)):
        1 + iterable[i]

# Using enumerate
def enumerate_loop(iterable):
    for i, val in enumerate(iterable):
        1 + val

# Manual indexing
def manual_indexing_loop(iterable):
    index = 0
    for item in iterable:
        1 + item
        index += 1

Xem số liệu hiệu suất cho từng phương pháp dưới đây:

from timeit import timeit

def measure(l, number=10000):
print "Measure speed for list with %d items" % len(l)
print "xrange: ", timeit(lambda :xrange_loop(l), number=number)
print "range: ", timeit(lambda :range_loop(l), number=number)
print "enumerate: ", timeit(lambda :enumerate_loop(l), number=number)
print "manual_indexing: ", timeit(lambda :manual_indexing_loop(l), number=number)

measure(range(1000))
# Measure speed for list with 1000 items
# xrange:  0.758321046829
# range:  0.701184988022
# enumerate:  0.724966049194
# manual_indexing:  0.894635915756

measure(range(10000))
# Measure speed for list with 100000 items
# xrange:  81.4756360054
# range:  75.0172479153
# enumerate:  74.687623024
# manual_indexing:  91.6308541298

measure(range(10000000), number=100)
# Measure speed for list with 10000000 items
# xrange:  82.267786026
# range:  84.0493988991
# enumerate:  78.0344707966
# manual_indexing:  95.0491430759

Kết quả là, sử dụng rangephương thức là cách nhanh nhất để liệt kê với 1000 mục. Đối với danh sách có kích thước> 10 000 mặt hàng enumeratelà người chiến thắng.

Thêm một số liên kết hữu ích dưới đây:


5
"Tính dễ đọc" Chênh lệch tốc độ trong phạm vi <1000 nhỏ là không đáng kể. Nó chậm hơn 3% trên một thước đo thời gian đã nhỏ.

Làm thế nào về việc cập nhật câu trả lời cho Python 3?
Georgy

14

Trước hết, các chỉ mục sẽ từ 0 đến 4. Ngôn ngữ lập trình bắt đầu đếm từ 0; đừng quên điều đó hoặc bạn sẽ bắt gặp một chỉ số nằm ngoài giới hạn. Tất cả những gì bạn cần trong vòng lặp for là một biến đếm từ 0 đến 4 như vậy:

for x in range(0, 5):

Hãy nhớ rằng tôi đã viết 0 đến 5 vì vòng lặp dừng một số trước mức tối đa. :)

Để có được giá trị của một chỉ mục sử dụng

list[index]

13

Đây là những gì bạn nhận được khi bạn truy cập chỉ mục trong forcác vòng lặp:

for i in enumerate(items): print(i)

items = [8, 23, 45, 12, 78]

for i in enumerate(items):
    print("index/value", i)

Kết quả:

# index/value (0, 8)
# index/value (1, 23)
# index/value (2, 45)
# index/value (3, 12)
# index/value (4, 78)

for i, val in enumerate(items): print(i, val)

items = [8, 23, 45, 12, 78]

for i, val in enumerate(items):
    print("index", i, "for value", val)

Kết quả:

# index 0 for value 8
# index 1 for value 23
# index 2 for value 45
# index 3 for value 12
# index 4 for value 78

for i, val in enumerate(items): print(i)

items = [8, 23, 45, 12, 78]

for i, val in enumerate(items):
    print("index", i)

Kết quả:

# index 0
# index 1
# index 2
# index 3
# index 4

12

Theo cuộc thảo luận này: http://bytes.com/topic/python/answers/464012-objects-list-index

Lặp lại vòng lặp

Thành ngữ hiện tại để lặp qua các chỉ mục sử dụng hàm dựng sẵn range:

for i in range(len(sequence)):
    # work with index i

Vòng lặp trên cả hai yếu tố và chỉ số có thể đạt được bằng thành ngữ cũ hoặc bằng cách sử dụng hàm tích hợp mới zip:

for i in range(len(sequence)):
    e = sequence[i]
    # work with index i and element e

hoặc là

for i, e in zip(range(len(sequence)), sequence):
    # work with index i and element e

thông qua http://www.python.org/dev/peps/pep-0212/


22
Điều này sẽ không hoạt động để lặp qua máy phát điện. Chỉ cần sử dụng liệt kê ().
Tadeck

Ngày nay, thành ngữ hiện tại là liệt kê, không phải là cuộc gọi phạm vi.
TankorSmash

và nó giống như câu trả lời cũ hơn: stackoverflow.com/a/522576/6451573
Jean-François Fabre

11

Bạn có thể làm điều đó với mã này:

ints = [8, 23, 45, 12, 78]
index = 0

for value in (ints):
    index +=1
    print index, value

Sử dụng mã này nếu bạn cần đặt lại giá trị chỉ mục ở cuối vòng lặp:

ints = [8, 23, 45, 12, 78]
index = 0

for value in (ints):
    index +=1
    print index, value
    if index >= len(ints)-1:
        index = 0

10

Giải pháp tốt nhất cho vấn đề này là sử dụng enumerate trong xây dựng chức năng python.
liệt kê trả về tuple
giá trị đầu tiên là chỉ số
giá trị thứ hai là phần tử của mảng tại chỉ mục đó

In [1]: ints = [8, 23, 45, 12, 78]

In [2]: for idx, val in enumerate(ints):
   ...:         print(idx, val)
   ...:     
(0, 8)
(1, 23)
(2, 45)
(3, 12)
(4, 78)

9

Trong câu hỏi của bạn, bạn viết "làm thế nào để tôi truy cập vào chỉ mục vòng lặp, từ 1 đến 5 trong trường hợp này?"

Tuy nhiên, chỉ mục cho một danh sách chạy từ số không. Vì vậy, sau đó chúng ta cần biết liệu thứ bạn thực sự muốn là chỉ mục và mục cho từng mục trong danh sách hay bạn thực sự muốn số bắt đầu từ 1. May mắn thay, trong Python, thật dễ dàng để thực hiện một hoặc cả hai.

Đầu tiên, để làm rõ, enumeratehàm lặp lại trả về chỉ mục và mục tương ứng cho mỗi mục trong danh sách.

alist = [1, 2, 3, 4, 5]

for n, a in enumerate(alist):
    print("%d %d" % (n, a))

Đầu ra cho ở trên là,

0 1
1 2
2 3
3 4
4 5

Lưu ý rằng chỉ mục chạy từ 0. Loại lập chỉ mục này là phổ biến giữa các ngôn ngữ lập trình hiện đại bao gồm Python và C.

Nếu bạn muốn vòng lặp của mình trải dài một phần của danh sách, bạn có thể sử dụng cú pháp Python chuẩn cho một phần của danh sách. Ví dụ: để lặp từ mục thứ hai trong danh sách lên đến nhưng không bao gồm mục cuối cùng, bạn có thể sử dụng

for n, a in enumerate(alist[1:-1]):
    print("%d %d" % (n, a))

Lưu ý rằng một lần nữa, chỉ mục đầu ra chạy từ 0,

0 2
1 3
2 4

Điều đó mang lại cho chúng tôi để start=nchuyển đổi cho enumerate(). Điều này chỉ đơn giản là bù đắp cho chỉ mục, bạn có thể chỉ cần thêm một số vào chỉ mục bên trong vòng lặp.

for n, a in enumerate(alist, start=1):
    print("%d %d" % (n, a))

mà đầu ra là

1 1
2 2
3 3
4 4
5 5

9

Nếu tôi lặp đi lặp lại nums = [1, 2, 3, 4, 5]tôi sẽ làm

for i, num in enumerate(nums, start=1):
    print(i, num)

Hoặc có được chiều dài như l = len(nums)

for i in range(l):
    print(i+1, nums[i])

7

Nếu không có giá trị trùng lặp trong danh sách:

for i in ints:
    indx = ints.index(i)
    print(i, indx)

1
Lưu ý rằng không nên sử dụng tùy chọn đầu tiên, vì nó chỉ hoạt động chính xác khi mỗi mục trong chuỗi là duy nhất.
Stam Kaly

2
Tùy chọn đầu tiên là O (n²), một ý tưởng khủng khiếp. Nếu danh sách của bạn dài 1000 phần tử, nó sẽ mất nhiều thời gian hơn 1000 lần so với sử dụng enumerate. Bạn nên xóa câu trả lời này.
Boris

5

Bạn cũng có thể thử điều này:

data = ['itemA.ABC', 'itemB.defg', 'itemC.drug', 'itemD.ashok']
x = []
for (i, item) in enumerate(data):
      a = (i, str(item).split('.'))
      x.append(a)
for index, value in x:
     print(index, value)

Đầu ra là

0 ['itemA', 'ABC']
1 ['itemB', 'defg']
2 ['itemC', 'drug']
3 ['itemD', 'ashok']

3

Bạn có thể sử dụng indexphương pháp

ints = [8, 23, 45, 12, 78]
inds = [ints.index(i) for i in ints]

EDIT Nổi bật trong nhận xét rằng phương pháp này không hoạt động nếu có trùng lặp ints, phương thức bên dưới sẽ hoạt động với mọi giá trị trong ints:

ints = [8, 8, 8, 23, 45, 12, 78]
inds = [tup[0] for tup in enumerate(ints)]

Hay cách khác

ints = [8, 8, 8, 23, 45, 12, 78]
inds = [tup for tup in enumerate(ints)]

nếu bạn muốn lấy cả chỉ mục và giá trị intsdưới dạng danh sách các bộ dữ liệu.

Nó sử dụng phương pháp enumerate trong câu trả lời được chọn cho câu hỏi này, nhưng với sự hiểu biết danh sách, làm cho nó nhanh hơn với ít mã hơn.


2

Câu trả lời đơn giản bằng While Loop:

arr = [8, 23, 45, 12, 78]
i = 0
while i<len(arr):
    print("Item ",i+1," = ",arr[i])
    i +=1

Đầu ra:

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


1

Để in bộ dữ liệu (chỉ mục, giá trị) theo cách hiểu danh sách bằng cách sử dụng forvòng lặp:

ints = [8, 23, 45, 12, 78]
print [(i,ints[i]) for i in range(len(ints))]

Đầu ra:

[(0, 8), (1, 23), (2, 45), (3, 12), (4, 78)]

1

Điều này phục vụ mục đích đủ tốt:

list1 = [10, 'sumit', 43.21, 'kumar', '43', 'test', 3]
for x in list1:
    print('index:', list1.index(x), 'value:', x)

4
Điều này sẽ bị hỏng nếu có các phần tử lặp lại trong danh sách như index()sẽ tìm kiếm lần xuất hiện đầu tiên x, không đề cập đến thời gian O ( n ^ 2 ) cần thiết để tra cứu từng phần tử.
Peter Szoldan

hoàn toàn đồng ý rằng nó sẽ không hoạt động cho các yếu tố trùng lặp trong danh sách. Sau tất cả, tôi cũng đang học trăn.
Sumit Kumar
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.