Python: удалить все индексы списка, удовлетворяющие определенному условию - PullRequest
4 голосов
/ 23 августа 2011

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

в массиве:

map = [[-1, 2], [5, -3], [2, 3], [1, -1], [7, 1]]

Я хочу удалить все пары, в которых любая координата равна <0, оставляя: </p>

map = [[2, 3], [7, 1]]

Моя проблемав том, что списки Python не могут иметь пробелов, поэтому если я зациклюсь так:

i = 0
for pair in map:
        for coord in pair:
            if coord < 0:
                del map[i]
    i += 1

Все индексы сдвигаются при удалении элемента, запутывая итерацию и вызывая всевозможные проблемы.Я пытался сохранить индексы плохих элементов в другом списке, а затем перебрать и удалить эти элементы, но у меня та же проблема: после того, как один из них исчез, весь список сдвигается, и индексы перестают быть точными.

Есть ли что-то, что мне не хватает?

Спасибо.

Ответы [ 8 ]

3 голосов
/ 23 августа 2011

Если список не большой, то проще всего создать новый список:

In [7]: old_map = [[-1, 2], [5, -3], [2, 3], [1, -1], [7, 1]]

In [8]: new_map=[[x,y] for x,y in a_map if not (x<0 or y<0)]

In [9]: new_map
Out[9]: [[2, 3], [7, 1]]

Вы можете выполнить это с old_map = new_map, если хотите сбросить другие пары.

Если список настолько велик, создание нового списка сопоставимого размера является проблемой, то вы можете удалить элементы из списка на месте - хитрость заключается в том, чтобы сначала удалить их из хвостовой части:

the_map = [[-1, 2], [5, -3], [2, 3], [1, -1], [7, 1]]
for i in range(len(the_map)-1,-1,-1):
    pair=the_map[i]
    for coord in pair:
        if coord < 0:
            del the_map[i]

print(the_map)

1010 * выходы *

[[2, 3], [7, 1]]

PS. map - это такая полезная встроенная функция Python. Лучше не называть переменную map, поскольку она переопределяет встроенную.

3 голосов
/ 23 августа 2011

Вы можете использовать список понимания для этого:

>>> mymap = [[-1, 2], [5, -3], [2, 3], [1, -1], [7, 1]]
>>> mymap = [m for m in mymap if m[0] > 0 and m[1] > 0]
>>> mymap
[[2, 3], [7, 1]]
1 голос
/ 23 августа 2011

Если у вас нет других ссылок на список map, лучше всего подойдет понимание списка:

map = [[a,b] for (a,b) in map if a > 0 and b > 0]

Если у вас есть другие ссылки и вам нужно фактически удалить элементы изсписок, на который ссылается map, необходимо перебрать копию map:

for coord in map[:]:
    if coord[0] < 0 or coord[1] < 0:
        map.remove(coord)
0 голосов
/ 12 ноября 2013

itertools.ifilter()/ifilterfalse() существует именно для этого: отфильтровать итерируемое по предикату (очевидно, не на месте).Более того, по возможности избегайте создания и выделения всего отфильтрованного объекта списка, просто переберите его:

import itertools

l = [(4,-5), (-8,2), (-2,-3), (4,7)]

# Option 1: create a new filtered list
l_filtered = list( itertools.ifilter(lambda p: p[0]>0 and p[1]>0, l) )

# Option 2:
for p in itertools.ifilter(lambda p: p[0]>0 and p[1]>0, l):
    ... <subsequent code on your filtered list> 
0 голосов
/ 24 августа 2011

Если список достаточно мал, более эффективно сделать копию, содержащую только те элементы, которые вам нужны, как подробно описано в других ответах.

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

def filter_in_place(func, target, invert=False):
    "remove all elements of target where func(elem) is false"
    pos = len(target)-1
    while pos >= 0:
        if (not func(target[pos])) ^ invert:
            del target[pos]
        pos -= 1

В вашем примере это можно применить следующим образом:

 >>> data = [[-1, 2], [5, -3], [2, 3], [1, -1], [7, 1]]
 >>> def is_good(elem):
         return elem[0] >= 0 and elem[1] >= 0
 >>> filter_in_place(is_good, data)
 >>> data
 [[2, 3], [7, 1]]

(Это просто ориентированная на список версия filter_in_place, которая поддерживает все базовые типы данных Python немного сложнее).

0 голосов
/ 23 августа 2011

Вы, вероятно, хотите вместо del pair.

0 голосов
/ 23 августа 2011

Лично я предпочитаю модификацию на месте:

li = [[-1, 2], [5, -3], [2, 3], [1, -1], [7, 1]]
print li,'\n'


N = len(li)
for i,(a,b) in enumerate(li[::-1], start=1):
    if a<0 or b<0:
        del li[N-i]
print li

->

[[-1, 2], [5, -3], [2, 3], [1, -1], [7, 1]] 

[[2, 3], [7, 1]]
0 голосов
/ 23 августа 2011

Если вы хотите сделать это на месте, без создания нового списка, просто используйте цикл for с индексом, идущим от len (map) -1 до 0.

for index in range(len(map)-1,-1,-1):
    if hasNegativeCoord(map[index]):
        del(map[index])

Не очень Pythonic,Я признаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...