У меня есть несколько соответствующих списков, каждый из которых содержит ровно 206 элементов. Количество элементов и значения этих элементов могут различаться в зависимости от того, что находится внутри файла, который читает программа.

Один из этих списков полностью состоит из целых чисел и используется в качестве основы для определения необходимости удаления элементов из всех списков. Мой код выглядит следующим образом:

toRemove = []
for element in myList:
    if element < int(cutoff):  # cutoff is specified by the user
        toRemove.append(myList.index(element))
toRemove = [int(element) for element in toRemove]
for element in toRemove:
    del myList2[element]
    del myList3[element]
    ...

Когда я запускаю >>>len(myList), Python возвращает 206 для всех списков, минус toRemove, поскольку toRemove определяется в соответствии с пользовательским вводом. Однако когда я использую toRemove, чтобы удалить эти индексы из всех списков, Python приветствует меня следующим:

Traceback (most recent call last):
  File "Test.py", line 104, in <module>
    del myList2[element]
IndexError: list assignment index out of range

Наибольшее значение в toRemove - 204 - в этом списке 205 индексов. toRemove не содержит значений ниже 0. При типизации [element] в [int (element)] выдается та же ошибка.

Список индексов для удаления:

[0, 1, 2, 3, 4, 5, 6, 7, 9, 12, 15, 16, 17, 18, 20, 21, 22, 25, 26, 28, 29, 30, 31, 33, 34, 37, 38, 39, 40, 41, 45, 46, 47, 48, 51, 52, 54, 56, 57, 58, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 72, 73, 74, 75, 77, 80, 84, 86, 87, 88, 89, 90, 91, 92, 94, 95, 96, 97, 98, 100, 101, 102, 103, 104, 106, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117, 118, 119, 120, 121, 124, 126, 127, 128, 129, 130, 133, 134, 135, 136, 138, 139, 140, 141, 142, 144, 145, 147, 149, 151, 110, 153, 154, 155, 157, 158, 161, 162, 163, 164, 165, 166, 167, 168, 169, 171, 173, 174, 175, 177, 178, 179, 180, 181, 182, 183, 184, 186, 187, 188, 189, 190, 192, 194, 195, 196, 197, 198, 200, 202, 203, 204]

Как видите, не меньше 0 или больше 205.

Список номеров для проверки:

[1032, 3882, 4182, 6880, 1170, 1968, 2085, 3548, 9111, 1122, 11987, 12718, 7606, 8391, 8890, 2574, 1447, 6257, 1457, 11430, 7202, 6891, 1495, 12372, 12907, 2243, 3984, 11236, 3462, 4790, 1103, 1044, 8805, 1404, 6259, 8655, 13695, 6505, 3758, 2378, 3303, 3360, 9102, 14768, 12154, 3079, 3307, 2416, 7043, 9910, 10050, 6497, 2407, 13477, 4118, 13762, 1351, 3645, 4092, 3785, 1565, 3721, 4982, 4166, 11234, 7306, 3608, 2437, 4022, 2688, 11411, 9126, 3526, 1398, 5657, 2336, 8775, 4073, 14731, 8885, 7264, 8399, 10268, 12131, 2129, 11420, 1334, 3675, 1055, 3544, 5301, 6608, 1482, 14221, 2254, 4288, 1178, 5032, 4973, 19573, 3855, 4360, 6408, 3040, 3220, 11735, 3591, 3807, 2590, 6169, 2300, 1332, 8996, 6680, 3537, 1048, 3505, 5960, 3480, 1486, 4782, 4607, 18269, 8258, 4514, 8069, 5698, 1753, 6314, 1634, 3688, 9249, 18783, 5514, 1409, 7197, 3789, 8172, 2718, 5535, 3508, 1769, 2503, 8178, 2414, 1175, 13069, 1916, 12297, 1732, 69609, 3047, 2300, 5752, 1106, 1522, 11687, 3020, 3929, 9407, 13449, 4644, 2399, 4317, 4917, 5476, 1194, 4016, 1496, 7788, 9365, 1223, 12289, 1624, 1410, 3321, 12930, 1806, 7154, 4961, 2798, 5571, 1931, 7912, 4944, 10963, 2427, 7514, 2425, 2649, 1303, 13568, 2923, 11225, 5822, 4268, 5962, 2422, 6978, 12393, 1331, 12749, 7460, 1683, 6403, 11972]

Вы можете заменить cutoff на 8000, так как это число, которое я использую для тестирования программы.

Что я делаю не так, и как мне исправить эту проблему?

0
Kenneth Martin 28 Июн 2019 в 11:54

4 ответа

Лучший ответ

Проблема, с которой вы сталкиваетесь, заключается в том, что список уменьшается при удалении из него элементов. Поскольку вы удаляете их по порядку спереди назад, более поздние индексы могут оказаться за пределами списка.

Рассмотрим этот более простой сценарий, чем ваш список с 200+ значениями:

lst = [0, 1, 2, 3]
indexes_to_remove = [2, 3]

for i in indexes_to_remove:
    del lst[i]

Вы получите то же исключение, что и в вашем примере. Причина в том, что после удаления индекса 2 последнее значение (3) равно также в индексе 2, поскольку список стал короче.

Есть несколько способов это исправить. Одним из вариантов будет удаление элементов, начинающихся в конце списка и работающих вперед. Таким образом, индексы, которые вы удаляете позже, всегда будут действительны, так как ничего до них не будет удалено. Поскольку вы гарантированно добавляете индексы по порядку (более или менее, см. Мое примечание ниже), вы можете просто выполнить итерацию в обратном порядке по ним с reversed:

for element in reversed(toRemove):
    del myList2[element]
    del myList3[element]

Другим вариантом будет вычисление модифицированного индекса по мере удаления некоторых значений из списков. Это не так уж сложно:

for i, element in enumerate(toRemove):
    del myList2[element-i]
    del myList3[element-i]

Наконец, может быть более эффективно перестроить все списки, чем использовать del для удаления некоторых значений из них. del some_list[some_index] занимает O(N) время для завершения, поэтому даже если вам придется циклически обходить индексы, чтобы пропустить несколько раз, это, вероятно, будет быстрее, чем выполнение набора del операций:

toRemove = set(toRemove)
myList2 = [v for i, v in enumerate(myList2) if i not in toRemove]
myList3 = [v for i, v in enumerate(myList3) if i not in toRemove]

Последнее замечание: в вашем текущем коде может быть еще одна ошибка при поиске всех индексов для удаления, если myList может иметь несколько копий с одинаковыми значениями. Это потому, что myList.index(element) всегда найдет first вхождение значения element, даже если вы просто перебираете его, когда оно появляется позже в списке. Вместо этого вам, вероятно, следует использовать enumerate для получения индексов во время итерации:

for i, element in enumerate(myList):
    if element < int(cutoff):  # cutoff is specified by the user
        toRemove.append(i)

Также может быть хорошей идеей изменить некоторые имена ваших переменных. В настоящее время вы используете element для всех ваших циклов, и иногда он ссылается на индекс (в другом списке), а в других случаях ссылается на значение. Более описательное имя поможет отличить эти случаи!

1
Blckknght 28 Июн 2019 в 09:11

Как сказано в комментариях, когда вы что-то удаляете, размер списка уменьшается, а дальнейшие элементы смещаются (пробела нет).

Что вы можете сделать, это:

1. Используйте то, что вы уже использовали, но сначала переходите от самого высокого индекса.

2. Используйте свой цикл, чтобы пометить элементы для удаления (например, назначив None или другое значение, не используемое в списке), вместо того, чтобы физически удалить его - и после цикла отфильтруйте их (например, используя {{ Х0 } } ) .

3. Используйте понимание списка и избегайте использования цикла в целом.

myList2 = [value for (index, value) in enumerate(myList2) if index not in toRemove]
1
h4z3 28 Июн 2019 в 09:09

Я бы сжал все списки, имея первый (int-valueed) список в качестве первого списка, затем отфильтровал список кортежей на основе первого элемента каждого кортежа и разархивировал отфильтрованный список кортежей обратно в несколько списков.

In [2]: list1 = [1, 2, 3, 4, 5]
In [3]: list2 = list('abcde')
In [4]: list3 = list('12345')
In [5]: list(map(list, zip(*[x for x in zip(list1, list2, list3) if x[0] >= 3])))
Out[5]: [[3, 4, 5], ['c', 'd', 'e'], ['3', '4', '5']]

Это то, что вы хотели бы иметь?

1
Grisha 28 Июн 2019 в 09:10

Изменение списка с помощью myList.sort(reverse=True) решило мою проблему. Спасибо!

0
Kenneth Martin 28 Июн 2019 в 09:18