удалить значение None из списка без удаления значения 0

245

Это был мой источник, с которого я начал.

Мой список

L = [0, 23, 234, 89, None, 0, 35, 9]

Когда я запускаю это:

L = filter(None, L)

Я получаю это результаты

[23, 234, 89, 35, 9]

Но это не то, что мне нужно, а то, что мне действительно нужно:

[0, 23, 234, 89, 0, 35, 9]

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

Как удалить значение None из списка, не удаляя значение 0?

mongotop
источник

Ответы:

355
>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> [x for x in L if x is not None]
[0, 23, 234, 89, 0, 35, 9]

Просто для забавы, вот как вы можете приспособиться filterк этому, не используя lambda, (я не рекомендовал бы этот код - это только для научных целей)

>>> from operator import is_not
>>> from functools import partial
>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> filter(partial(is_not, None), L)
[0, 23, 234, 89, 0, 35, 9]
jamylak
источник
23
Менее элегантная filterверсия: filter(lambda x: x is not None, L)- Вы могли бы избавиться от lambdaиспользования, partialи operator.is_notя думаю, но, вероятно, оно того не стоит, так как list-comp намного чище.
Мгилсон
3
@mgilson Ого, я даже не знал, что is_notсуществует! Я думал, что это только is_, я собираюсь добавить это просто для удовольствия
jamylak
@jamylak - Да. Это на самом деле беспокоит меня, что is_notсуществует и not_inне существует. Я действительно думаю, что это not_inдолжно быть превращено в волшебный метод __not_contains__... посмотрите вопрос, который я задал некоторое время назад, и комментарий, который я сделал ответчику ... и все еще не чувствую, что он решен.
Мгилсон
@mgilson Я думаю, что при том же предположении я просто предположил, что его не существует. Я думаю, вы можете просто использовать filterfalseили что-то в зависимости от
варианта
@jamylak - Да. Моя главная проблема заключается в том, x > yчто not x <= yв python ничего не подразумевается, потому что вы можете делать что-либо в __lt__и __le__, поэтому, почему следует x not in yподразумевать not x in y(тем более, not inчто он имеет свой собственный байт-код?)
mgilson
136

FWIW, Python 3 облегчает эту проблему:

>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> list(filter(None.__ne__, L))
[0, 23, 234, 89, 0, 35, 9]

В Python 2 вместо этого вы использовали бы понимание списка:

>>> [x for x in L if x is not None]
[0, 23, 234, 89, 0, 35, 9]
Раймонд Хеттингер
источник
+1 ли вы рекомендуете использовать __ne__так , как противоположность partialи ne?
jamylak
1
@jamylak Да, это быстрее, немного легче писать и немного яснее.
Рэймонд Хеттингер
Рассмотрите возможность использования operatorмодуля.
правостороннее
12
Что такое __ne__?
DrMcCleod
11
@DrMcCleod Внутреннее выражение x != yвызывает, x.__ne__(y)где ne означает «не равно». Таким образом, None.__ne__это связанный метод, который возвращает True при вызове с любым значением, отличным от None . Например, при bm = None.__ne__вызове с bm(10)возвратом возвращается значение NotImplemented, имеющее значение true, и bm(None)возвращается значение False .
Рэймонд Хеттингер
17

Используя понимание списка, это можно сделать следующим образом:

l = [i for i in my_list if i is not None]

Значение l:

[0, 23, 234, 89, 0, 35, 9]
DotPi
источник
1
Это решение уже найдено в верхнем ответе, или я что-то упустил?
Qaswed
16

Для Python 2.7 (см. Ответ Раймонда, для эквивалента Python 3):

Желая узнать, является ли что-то «не None» настолько распространенным в python (и других языках OO), что в моем Common.py (который я импортирую в каждый модуль с помощью «из общего импорта *») я включаю следующие строки:

def exists(it):
    return (it is not None)

Затем, чтобы удалить элементы None из списка, просто выполните:

filter(exists, L)

Я считаю, что это легче читать, чем соответствующее понимание списка (которое Раймонд показывает, как его версия Python 2).

ToolmakerSteve
источник
Я бы предпочел решение Raymonds для Python 3, а затем понимание списка для Python 2. Но если бы мне пришлось идти по этому пути, я бы предпочел partial(is_not, None)это решение. Я считаю, что это будет медленнее (хотя это не слишком важно). Но с парой импортных модулей Python в этом случае не требуется настраиваемая функция
jamylak
12

Ответ @jamylak довольно приятный, однако, если вы не хотите импортировать пару модулей просто для выполнения этой простой задачи, напишите свой собственный lambdaна месте:

>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> filter(lambda v: v is not None, L)
[0, 23, 234, 89, 0, 35, 9]
В
источник
Вы, очевидно, не правильно прочитали мое решение, а [x for x in L if x is not None]другой код был просто дополнением, которое я прямо заявил, что не рекомендую
jamylak
1
@jamylak - я читал, но вы не включили это решение. - Также не уверен, почему вы редактируете ответы людей 4-5 лет назад.
AT
5

Итерация против пространства , использование может быть проблемой. В разных ситуациях профилирование может показывать, что оно «быстрее» и / или «меньше памяти».

# first
>>> L = [0, 23, 234, 89, None, 0, 35, 9, ...]
>>> [x for x in L if x is not None]
[0, 23, 234, 89, 0, 35, 9, ...]

# second
>>> L = [0, 23, 234, 89, None, 0, 35, 9]
>>> for i in range(L.count(None)): L.remove(None)
[0, 23, 234, 89, 0, 35, 9, ...]

Первый подход (как и было предложено @jamylak , @Raymond Hettinger и @Dipto ) создает копию списка в памяти, что может быть дорогостоящим для большого списка с несколькоNone записями.

Второй подход проходит через список один раз, а затем снова каждый раз , пока не Noneбудет достигнут. Это может потребовать меньше памяти, и список будет уменьшаться. Уменьшение размера списка может ускорить появление большого количества Noneзаписей в начале, но наихудший случай будет, если многоNone записей появятся сзади.

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

Выбор любого подхода, вероятно, не будет иметь значения в обычных ситуациях. Это становится более предпочтительным обозначением. На самом деле, в этих необычных обстоятельствах numpyили cythonмогут быть полезными альтернативами вместо попыток микроуправления оптимизацией Python.

Kevin
источник
Совсем не фанат этого, единственное преимущество, которое вы заявляете с этим решением, состоит в том, что список может быть настолько огромным, что создание дублирующего списка в памяти может быть дорогостоящим. Что ж, тогда ваше решение будет еще более дорогостоящим, потому что вы сканируете весь список, L.count(None)а затем звоните .remove(None)несколько раз, что делает это O(N^2)Ситуация, которую вы пытаетесь решить, не должна рассматриваться таким образом, данные должны быть реструктурированы в базу данных или файл вместо этого, если это слишком интенсивно.
jamylak
@jamylak Правда, но не все реальные ситуации или данные допускают такую ​​гибкость. Например, прокачка «устаревших» геопространственных данных с помощью одноразового анализа в системе без большого объема памяти. Кроме того, необходимо учитывать время программирования и время выполнения. Люди часто обращаются к Python из-за экономии времени на разработку. Этим ответом я обращаю внимание на тот факт, что память может стоить учитывать, но в конце я заявляю, что это в основном индивидуальное предпочтение в нотации. Я также отмечаю, что знание данных важно. O(n^2)только когда весь список есть None.
Кевин
Было бы интересно, если бы у вас был практический пример, где этот ответ является лучшим решением, я склонен думать, что во всех случаях будет лучший подход. Например numpy, можно было бы обработать этот тип операции более оптимизированным способом
jamylak
@jamylak Если честно, я использовал numpyв последние годы, но это отдельный навык. Если Lсоздается как numpy.arrayвместо Python list, то L = L[L != numpy.array(None)](stackoverflow.com/a/25255015/3003133), вероятно, лучше, чем любой, но я не знаю подробностей реализации для обработки против памяти ниже. По крайней мере, он создает массив логических значений двойной длины для маски. Таким образом, синтаксис сравнения внутри оператора доступа (индекса) является новым для меня. Эта дискуссия также привлекла мое внимание dtype=object.
Кевин
Это обсуждение становится слишком абстрактным, и я не думаю, что вы сможете привести мне один реальный пример из вашей жизни, когда этот ответ - правильный подход к реструктуризации данных, как я упоминал ранее.
jamylak
2
from operator import is_not
from functools import partial   

filter_null = partial(filter, partial(is_not, None))

# A test case
L = [1, None, 2, None, 3]
L = list(filter_null(L))
med_abidi
источник
6
Пожалуйста, предоставьте ОП подробные сведения, а не просто код.
Лоран Лапорт
1
Я сделал. Что ты думаешь?
med_abidi
Ну, это не отвечает на вопрос ОП. Рассмотрите этот ответ вместо: stackoverflow.com/a/16096769/1513933
Лоран Лапорт
Да ты прав. Возникла проблема с частичным фильтром.
med_abidi
2

Если это весь список списков, вы можете изменить ответ sir @ Raymond

L = [ [None], [123], [None], [151] ] no_none_val = list(filter(None.__ne__, [x[0] for x in L] ) ) для Python 2 однако

no_none_val = [x[0] for x in L if x[0] is not None] """ Both returns [123, 151]"""

<< list_indice [0] для переменной в списке, если переменная не None >>

Skrmnghrd
источник
1

Скажите, что список как ниже

iterator = [None, 1, 2, 0, '', None, False, {}, (), []]

Это вернет только те предметы, чьи bool(item) is True

print filter(lambda item: item, iterator)
# [1, 2]

Это эквивалентно

print [item for item in iterator if item]

Чтобы просто отфильтровать None:

print filter(lambda item: item is not None, iterator)
# [1, 2, 0, '', False, {}, (), []]

Эквивалентно:

print [item for item in iterator if item is not None]

Чтобы получить все предметы, которые оценивают как ложные

print filter(lambda item: not item, iterator)
# Will print [None, '', 0, None, False, {}, (), []]
theBuzzyCoder
источник