видаліть зі списку значення None, не видаляючи значення 0


244

Це було моє джерело, з якого я починав.

Мій список

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?

Відповіді:


354
>>> 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]

23
Менш елегантний filterваріант: filter(lambda x: x is not None, L)- Ви могли б позбутися від lambdaвикористання partialі operator.is_notя думаю, але це, ймовірно , не варто , так як список-Comp так багато чистіше.
mgilson

3
@mgilson О, уау, я навіть не знав, що is_notіснує! Я думав, що це тільки is_, я додам, що просто заради розваги
jamylak

@jamylak - Так. Це насправді турбує мене, що is_notіснує і not_inне існує. Я насправді думаю, що це not_inслід перетворити на магічний метод __not_contains__... дивіться запитання, яке я заздалегідь задав, і коментар, який я зробив відповідачу ... і все ще не відчуваю, що це вирішено.
mgilson

@mgilson Я думаю, що за тим самим припущенням я просто припустив, що його не існує. Я здогадуюсь, ви можете просто використовувати filterfalseабо щось залежно від випадку використання
jamylak

@jamylak - Так. Моя головна проблема полягає в тому , що x > yне має на увазі not x <= yв пітона , тому що ви можете зробити що - небудь в __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, що як справжнє значення, і bm(None)повертає False .
Реймонд Хеттінгер

17

Використовуючи розуміння списку, це можна зробити наступним чином:

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

Значення l дорівнює:

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

Це рішення вже знайдено у верхній відповіді, чи я щось пропускаю?
Qaswed

16

Для Python 2.7 (див. Відповідь Реймонда, для еквівалента Python 3):

Бажаючи дізнатись, чи є щось "ні", настільки поширене в python (та інших мовах ОО), що в моєму файлі Common.py (який я імпортую до кожного модуля із "із загального імпорту *") я включаю ці рядки:

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

Потім, щоб видалити жоден елемент зі списку, просто виконайте:

filter(exists, L)

Мені це легше читати, ніж відповідне розуміння списку (яке показує Реймонд, як його версія Python 2).


Я вважаю за краще рішення 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.


Зовсім не прихильник цього, вся перевага, яку ви заявляєте за допомогою цього рішення, полягає в тому, що список може бути настільки величезним , що складання дублікату списку в пам'яті може бути дорогим. Добре, тоді ваше рішення буде ще дорожчим, оскільки ви скануєте весь список, 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), мабуть, краще, ніж будь-який, але я не знаю деталі реалізації для обробки vs пам'яті під нею. Це принаймні створює дублікат довжини масиву булів для маски. Синтаксис порівняння всередині оператора доступу (індексу), таким чином, для мене новий. Ця дискусія також принесла мою увагу 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))

6
Будь ласка, надайте детальну інформацію до ОП, а не лише код.
Лоран ЛАПОРТЕ

1
Я зробила. Що ти думаєш?
med_abidi

Ну, це не відповідає на питання ОП. Розгляньте замість цього відповідь: stackoverflow.com/a/16096769/1513933
Лоран ЛАПОРТ

Так, ти маєш рацію. Виникла проблема з частковим фільтром.
med_abidi

2

Якщо це весь список списків, ви можете змінити відповідь сер @ Реймонда

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] для змінної у списку, якщо змінна - немає >>


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, {}, (), []]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.