2016-06-13 2 views
1

У меня есть два спискаУдаление элементы, соответствующие «None» в списках

x = [ None , None , "foo" , "bar" ] 
y = [ "bar" , "foo" , "foo" ,"bar"] 

len(x) == len(y) 

Я хочу, чтобы проверить, существует элемент в списке x, который None затем удалить этот элемент и удалить соответствующий элемент у тоже. хотел удалить x[0] == None, поэтому удалить x[0] и y[0] из x и y

результат должен быть:

x = ["foo","bar"] 
y = ["foo","bar"] 

я попробовал совсем не-вещий путь, который дал мне «индекс списка из диапазона» ошибка :

for i in range(0,len(x)): 
    if(x[i] == None): 
     x.remove(x[i]) 
     y.remove(y[i]) 
+0

Ошибка списка «индекс за пределами диапазона», поскольку в вашем цикле for вы определяете, что индекс идет от 0 ... len (x) - 1. Затем вы продолжаете и удаляете элементы из списка, что уменьшает длину списка. Таким образом, вы пытаетесь получить доступ к большему количеству элементов, чем оно содержит, если вы когда-либо удаляете элемент. – datosh

ответ

3

Используя метод zip вы можете сделать это очень красиво:

x, y = zip(*[(e_x, e_y) for e_x, e_y in zip(x, y) if e_x is not None]) 

Здесь вы перебираете оба списка сразу, создавая новый список с кортежами, содержащими элементы x и y. Эти кортежи добавляются только в том случае, если элемент из x e_x не является None. Внешний zip преобразует список кортежей обратно в два отдельных списка.

Редактировать: Как указал Donkey Kong в комментарии, лучше использовать is not None вместо != None. Я обновил код соответствующим образом.

+2

Приятно, хотя лучше использовать 'не None ', вообще говоря. [См. Здесь] (http://jaredgrubb.blogspot.nl/2009/04/python-is-none-vs-none.html). – miradulo

0

Сначала пройти и выяснить, что вам нужно удалить:

remove_ix = {ix for ix, val in enumerate(x) if val is None} 

Теперь вы можете использовать его для фильтрации x и y:

x = [item for ix, item in enumerate(x) if ix not in remove_ix] 
y = [item for ix, item in enumerate(y) if ix not in remove_ix] 

Обратите внимание, что с вашей версией, вы в конечном итоге пропустите индексы и, вероятно, получите IndexError s, потому что если начальная длина списка равна N, и вы удаляете один i Тем не менее, вы все равно будете зацикливаться N раз, но этот список теперь N-1. Кроме того, с list.remove, вы не можете гарантировать, что вы удаляете элемент правильно если есть дубликаты (которые есть в вашем примере)

3

Давайте называть свои списки хз и YS.

ys = [y for (x, y) in zip(xs, ys) if x] 
xs = [x for x in xs if x] 

должен сделать трюк.

+0

Мне нравится этот ответ ... Может быть, больше, чем мое :-) – mgilson

+0

Почему не просто 'xs, ys = [(x, y) для (x, y) в zip (xs, ys), если x]'? Сохраняет выполнение другого цикла. – SvbZ3r0

+0

И условие лучше, так как 'if x is not None', чтобы избежать пропусков' 0 's – SvbZ3r0

0

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

x_list = [ None , None , "foo" , "bar" ] 
y_list = [ "bar" , "foo" , "foo" ,"bar"] 
d = {val:y_list[i] for i,val in enumerate(x_list) if val is not None} 
new_l_y = d.values() 
new_l_x = d.keys() 

ПРИМЕЧАНИЕ: Вы бы пропустить порядок элементов, но сохранить соответствие элементов. Если дело касается заказа, вы можете использовать OrderedDict.

from collections import OrderedDict 
d = OrderedDict((val,y_list[i]) for i,val in enumerate(x_list) if val is not None) 
new_l_y = d.keys() 
new_l_y = d.values() 
0

Использования zip для удаления элементов, которые None (в й) от совпадающих пар х и у, а затем использовать другой zip(*...) перенести список списков обратно в ссылках х и у:

x, y = zip(*[[ix, iy] for ix, iy in zip(x, y) if ix is not None]) 
Смежные вопросы