Почему этот итеративный код, расширяющий список, дает 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

Могу я спросить, почему не работает решение ОП? Зачем использовать приложение?
Хелен

Ответы:


318

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 - это тип списка, а не массива. С типом списка, я не думаю, что это подписка. Очень сбивает с толку, если приходят с других языков.
Нгуай Аль

@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[:]

эта вторая конструкция аккуратна
Джавадба

2
Если единственная цель состоит в том, чтобы скопировать список, вы можете просто сказать, что j = list (i) Я думаю, что вопрос больше в поведении списков, а не в том, чтобы конкретно нуждаться в способе копирования элементов.
Стив Мейн

10
j.append(l)

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


7

Я думаю, что вставка метода Python - это то, что вы ищете:

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

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 () предпочтительнее.
Мартин Питерс

На самом деле, почему я так отвечаю на этот вопрос, я тоже удивлен: 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, сопоставление обычно является неправильной структурой данных, особенно когда сопоставления не имеют срезов или реверсирования, поскольку они не предназначены для передачи какого-либо конкретного порядка.
Мартин Питерс

2

Еще один способ:

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

В этом случае jбудет массив NumPy


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.