Чому цей ітеративний код розширення списку надає IndexError: індекс присвоєння списку поза діапазоном?


194

Будь ласка, врахуйте наступний код:

i = [1, 2, 3, 5, 8, 13]
j = []
k = 0

for l in i:
    j[k] = l
    k += 1

print j

Вихід (Python 2.6.6 на Win 7 32-розрядний):

> Traceback (most recent call last): 
>     j[k] = l IndexError: list assignment index out of range

Я думаю, це щось просте, я не розумію. Може хтось прояснить це?


7
appendє правильним рішенням для вашого випадку використання, однак у списку python є метод вставки, який може вставлятись безпосередньо на i-ту позицію в списку. j.insert(k, l)
opensourcegeek

Чи можу я запитати, чому рішення ОС не працює? Навіщо використовувати додавання?
Олена

Відповіді:


317

jце порожній список, але ви намагаєтесь записати елемент [0]у першій ітерації, яка ще не існує.

Спробуйте скористатися наступним, щоб додати новий елемент до кінця списку:

for l in i:
    j.append(l)

Звичайно, ти ніколи цього не робив би на практиці, якби все, що ти хотів зробити, було скопіювати наявний список. Ви просто зробите:

j = list(i)

Крім того, якщо ви хочете використовувати список Python як масив іншими мовами, тоді ви можете попередньо створити список з його елементами, встановленими на нульове значення ( Noneу прикладі нижче), а пізніше перезаписати значення в конкретні позиції:

i = [1, 2, 3, 5, 8, 13]
j = [None] * len(i)
#j == [None, None, None, None, None, None]
k = 0

for l in i:
   j[k] = l
   k += 1

Слід усвідомити, що listоб’єкт не дозволить призначити значення індексу, який не існує.


2
Добре, дуже дякую. Я не знав, кого похвалити, оскільки є три майже однакові відповіді. Я думаю, це найбільш описово. Ура
Владан

Я бачу, що це може бути дуже заплутано для тих, хто походить з інших мов, таких як PHP або C. j - це тип списку, а не масив. Що стосується типу списку, я не думаю, що це можна підписати. Дуже заплутано, якщо виходять з інших мов.
Nguai al

@Nguaial Тип списку можна підписати, але ви можете отримати доступ лише до вже існуючих елементів - ви не можете створити елемент, намагаючись записати в індекс, який знаходиться поза діапазоном. j [0] = "foo" буде працювати, якщо в списку вже є хоча б один елемент.
Стів

52

Ваш інший варіант - ініціалізувати j:

j = [None] * len(i)

3
Ви хочете використовувати len (i), а не max.
Стів

25

Робіть j.append(l)замість цього j[k] = lі kвзагалі уникайте .


2
Коротший (пітонічний?) Шлях може бутиj+=[l]
Олег Припін

2
@BlaXpirit: Я думаю, це покладе тягар для збирача сміття.
хачик

2
@BalXpirit: Враховуючи, що це економить лише декілька символів (тим більше, що вам потрібно додати пробіли, щоб це було прийнятним), і .appendце набагато частіше (можливо, з тієї причини - я думаю, що це трохи легше зрозуміти), не справді вище в будь-якому випадку. (Редагувати @khachik: Ні, +=змінює на місці)

15

Ви також можете використати розуміння списку:

j = [l for l in i]

або зробити його копію за допомогою оператора:

j = i[:]

що друге будівництво охайне
javadba

2
Якщо єдиною метою є копіювання списку, ви можете просто сказати j = list (i) Я думаю, що питання стосується скоріше поведінки списків, а не конкретного необхідності способу копіювання елементів.
Стів

10
j.append(l)

Також уникайте використання малих букв "L", оскільки їх легко плутати з "1"


7

Я думаю, що вставка методу Python - це те, що ви шукаєте:

Вставляє елемент x у положення i. list.insert (i, x)

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

array.insert(1,20)

print(array)

# prints [1,2,20,3,4,5]

1
Немає сенсу використовувати, insertколи це appendбуло передбачено спеціально для цієї мети.
holdenweb

На інформаційній інформації ваш код насправді друкує [1, 20, 2, 3, 4, 5].
holdenweb

Ви вставили в індекс 1, переміщуючи індекси 1 і далі. Вставлене значення не закінчується в індексі 2. Iist.insert () дійсно потрібен лише тоді, коли ви не хочете додавати елемент в кінці списку; питання тут робить саме це, так що list.append () є кращим.
Martijn Pieters

Насправді, чому я відповідаю на це питання так, я також здивований: D Не знаю, що я думав :) Це саме "list.append ()", що є прийнятою відповіддю. Я думаю, що це допомагає людям або дає ідею вирішити їхні проблеми, щоб отримати 5 звернень.
Мехмет Каган

5

Ви можете використовувати словник (подібний до асоціативного масиву) для j

i = [1, 2, 3, 5, 8, 13]
j = {} #initiate as dictionary
k = 0

for l in i:
    j[k] = l
    k += 1

print j

надрукує:

{0: 1, 1: 2, 2: 3, 3: 5, 4: 8, 5: 13}

Для послідовних індексів, що починаються з 0, відображення зазвичай є неправильною структурою даних, особливо коли відображення не мають зрізування чи реверсування, оскільки вони не призначені для передачі конкретного порядку.
Martijn Pieters

2

Ще один спосіб:

j=i[0]
for k in range(1,len(i)):
    j = numpy.vstack([j,i[k]])

У цьому випадку jбуде нумерований масив


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.