2010-10-02 3 views
445

Я хочу удалить все пустые строки из списка строк в python.Удалить пустые строки из списка строк

Моя идея выглядит следующим образом:

while '' in str_list: 
    str_list.remove('') 

Есть ли еще вещий способ сделать это?

+5

вы должны * никогда * изменить список вы итерацию. Кроме того, ваш цикл будет удалять только с начала вашего списка, как только непустая строка будет fiund. –

+29

@Ivo, ни одно из этих утверждений не является истинным. Вы никогда не должны изменять список, в котором выполняется повторное использование с помощью 'for x in list'. Если вы используете' while loop', тогда это нормально. описанный цикл удалит пустые строки, пока не будет больше пустых строк, а затем остановится. Я на самом деле даже не рассматривал вопрос (просто название), но я ответил с помощью того же цикла, что и возможность! Если вы не хотите использовать понимание или фильтры для памяти, это очень pythonic решение. – aaronasterling

+5

@AaronMcSmooth Вы правы, я сделал неправильные предположения о цикле, потому что я выглядел недостаточно хорошо. Мой плохой –

ответ

749

I будет использовать filter:

str_list = filter(None, str_list) # fastest 
str_list = filter(bool, str_list) # fastest 
str_list = filter(len, str_list) # a bit slower 
str_list = filter(lambda item: item, str_list) # slower than list comprehension 

Python 3 возвращает итератор из filter, поэтому должны быть обернуты в вызове list()

str_list = list(filter(None, str_list)) # fastest 

(и т.д.)

Тесты:

>>> timeit('filter(None, str_list)', 'str_list=["a"]*1000', number=100000) 
2.4797441959381104 
>>> timeit('filter(bool, str_list)', 'str_list=["a"]*1000', number=100000) 
2.4788150787353516 
>>> timeit('filter(len, str_list)', 'str_list=["a"]*1000', number=100000) 
5.2126238346099854 
>>> timeit('[x for x in str_list if x]', 'str_list=["a"]*1000', number=100000) 
13.354584932327271 
>>> timeit('filter(lambda item: item, str_list)', 'str_list=["a"]*1000', number=100000) 
17.427681922912598 
+9

или 'filter (len, str_list)' –

+2

@ Ник, я слишком много думал. Как насчет использования 'bool'? Я сделал быстрый тест, это быстрее, чем 'len'. – livibetter

+0

@livibetter, о да! Почему бы не изменить свой ответ, чтобы включить его? –

136

List comprehensions

strings = ["first", "", "second"] 
[x for x in strings if x] 

Выход: ['first', 'second']

Edit: укороченный, как было предложено

+37

Это решение в x9 раз медленнее, чем '' filter (None, my_list) ''. – Kee

+13

@kee Не имеет значения, медленнее, чем filter(). список представляет собой питоновское решение. – Tritium21

+0

@ Tritium21 Я думаю, что ** ** имеет значение, если вы хотите эффективный код, независимо от проблем с пифоном. –

-2

Loop через существующий список строк, а затем проверить на пустую строку, если он не пустой заполнить новую строку список с непустыми значениями, а затем заменить старый список строк на новый список строк

3

В зависимости от размера вашего списка, это может быть наиболее эффективным, если вы используете list.remove(), а не создавать новый список:

l = ["1", "", "3", ""] 

while True: 
    try: 
    l.remove("") 
    except ValueError: 
    break 

Это имеет преимущество, не создавая новый список, но тот недостаток, из-за необходимости искать с начала каждый раз, хотя в отличие от использования while '' in l, как было предложено выше, он требует только один раз на вхождение '' (безусловно, есть способ сохранить лучшее из обоих методов, но это сложнее).

+0

Вы можете редактировать список на месте, выполнив 'ary [:] = [e для e в ary if e]'. Гораздо чище и не использует исключения для потока управления. –

53

фильтр на самом деле имеет специальный вариант для этого:

filter(None, sequence) 

Он будет отфильтровывать все элементы, которые оценивают в значение False. Не нужно использовать фактические вызываемые здесь такие как bool, len и т. Д.

Это столь же быстро, как карта (BOOL, ...)

+4

Это идиома питона, на самом деле. Это также единственный раз, когда я все еще использую filter(), понимание списков перехватило всюду. – kaleissin

+0

Это тот же ответ, что и http://stackoverflow.com/a/3845453/1224827 – Blairg23

4

Использование filter:

newlist=filter(lambda x: len(x)>0, oldlist) 

недостатков использования фильтра, как отметил, что это происходит медленнее, чем альтернативные варианты; тоже, lambda обычно дорого.

Или вы можете пойти на самый простой и самый итерационный всего:

# I am assuming listtext is the original list containing (possibly) empty items 
for item in listtext: 
    if item: 
     newlist.append(str(item)) 
# You can remove str() based on the content of your original list 

это наиболее интуитивный из методов, и делает это в приличное время.

+7

Добро пожаловать в SO. Вы не были проигнорированы. На вас не напал какой-нибудь бесполезный спутник. Вам была предоставлена ​​обратная связь. Усиление: ваш предложенный первый аргумент для фильтра хуже, чем 'lambda x: len (x)', который хуже, чем 'lambda x: x', который является наихудшим из 4-х решений в выбранном ответе. Правильное функционирование является предпочтительным, но недостаточно. Наведите курсор на кнопку downvote: он говорит: «Этот ответ не полезен». –

+7

... и вы не должны использовать имя встроенного типа 'list' в качестве переменной. –

8

Вместо x, я бы использовал, если X! = '', Чтобы просто удалить пустые строки. Например:

str_list = [x for x in str_list if x != ''] 

Это сохранит тип данных None в вашем списке. Кроме того, если ваш список имеет целые числа, а 0 - один из них, он также будет сохранен.

Например,

str_list = [None, '', 0, "Hi", '', "Hello"] 
[x for x in str_list if x != ''] 
[None, 0, "Hi", "Hello"] 
+1

Если у ваших списков есть разрозненные типы (кроме None), у вас может возникнуть большая проблема. – Tritium21

+0

Какие типы? Я пробовал с int и другими числовыми типами, строками, списками, tupes, sets и None и никаких проблем там. Я мог видеть, что если есть какие-то пользовательские типы, которые не поддерживают метод str, может возникнуть проблема. Должен ли я беспокоиться о других? – thiruvenkadam

+1

Если у вас есть 'str_list = [None, '', 0," Hi ", ''," Hello "]', это признак плохо разработанного приложения. У вас не должно быть * более одного интерфейса (типа) и None в том же списке. – Tritium21

14
>>> lstr = ['hello', '', ' ', 'world', ' '] 
>>> lstr 
['hello', '', ' ', 'world', ' '] 

>>> ' '.join(lstr).split() 
['hello', 'world'] 

>>> filter(None, lstr) 
['hello', ' ', 'world', ' '] 

Сравнить время

>>> from timeit import timeit 
>>> timeit('" ".join(lstr).split()', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000) 
4.226747989654541 
>>> timeit('filter(None, lstr)', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000) 
3.0278358459472656 

Обратите внимание, что filter(None, lstr) не удаляет пустые строки с пробелом ' ', это только чернослив прочь '' пока ' '.join(lstr).split() удаляет обоих.

Чтобы использовать filter() с пробельных строк удалены, это занимает гораздо больше времени:

>>> timeit('filter(None, [l.replace(" ", "") for l in lstr])', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000) 
18.101892948150635 
+0

не будет работать, если у вас есть пробел между строкой слова. например: ['hello world', '', 'hello', '']. >> ['helloworld', '', 'hello', ''] есть ли у вас какое-либо другое решение для хранения пробелов внутри элемента в списке, но удаление других? –

+0

который не будет работать? –

+0

'' .join (lstr) .split() Я пробовал! –

-2
str_list = ['2', '', '2', '', '2', '', '2', '', '2', ''] 

for item in str_list: 
    if len(item) < 1: 
     str_list.remove(item) 

Короткий и сладкий.

-3

filter(None, str) не удаляет пустые строки с пробелом '', это только сокращает '' и ''.

join(str).split() удаляет оба. но если ваш элемент списка, имеющего пространства, то это изменит список ваших элементов и потому, что это первое присоединение все ваши элементы списка затем spiting их пространство так, Вы должны использовать: -

str = ['hello', '', ' ', 'world', ' '] 
print filter(lambda x:x != '', filter(lambda x:x != ' ', str)) 

Это удалит как и выиграл» т эффект ваши элементы также как: -

str = ['hello', '', ' ', 'world ram', ' '] 
print ' '.join(lstr).split() 
print filter(lambda x:x != '', filter(lambda x:x != ' ', lstr)) 

выход: -

[ 'привет', 'мир', 'баран'] < ------------- - выход ' '.join(lstr).split()
['hello', 'world ram']

7

Ответ от @ Ib33X замечательный. Если вы хотите удалить каждую пустую строку, после удаления. вам также нужно использовать метод полосы. В противном случае он также вернет пустую строку, если она имеет пробелы. Например, «» будет действительным и для этого ответа. Таким образом, может быть достигнуто.

strings = ["first", "", "second ", " "] 
[x.strip() for x in strings if x.strip()] 

Ответ на этот вопрос будет ["first", "second"].
Если вы хотите использовать метод filter, вы можете сделать это как
list(filter(lambda item: item.strip(), strings)). Это дает тот же результат.

+1

Лучший способ, на мой взгляд. Особенно, если в массиве есть целые строки вместо целых чисел. –

3

Как сообщает Aziz Altofilter(None, lstr) не удаляет пустые строки с пробелом ' ', но если вы уверены, что LSTR содержит только строку, которую вы можете использовать filter(str.strip, lstr)

>>> lstr = ['hello', '', ' ', 'world', ' '] 
>>> lstr 
['hello', '', ' ', 'world', ' '] 
>>> ' '.join(lstr).split() 
['hello', 'world'] 
>>> filter(str.strip, lstr) 
['hello', 'world'] 

Сравнить время на моем компьютере

>>> from timeit import timeit 
>>> timeit('" ".join(lstr).split()', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000) 
3.356455087661743 
>>> timeit('filter(str.strip, lstr)', "lstr=['hello', '', ' ', 'world', ' ']", number=10000000) 
5.276503801345825 

Самое быстрое решение для удаления '' и пустые строки с пробелом ' ' остается ' '.join(lstr).split().

Как сообщается в комментарии, ситуация другая, если ваши строки содержат пробелы.

>>> lstr = ['hello', '', ' ', 'world', ' ', 'see you'] 
>>> lstr 
['hello', '', ' ', 'world', ' ', 'see you'] 
>>> ' '.join(lstr).split() 
['hello', 'world', 'see', 'you'] 
>>> filter(str.strip, lstr) 
['hello', 'world', 'see you'] 

Вы можете видеть, что filter(str.strip, lstr) сохранить строки с пробелами на нем, но ' '.join(lstr).split() разделит эти строки.

+1

Это работает, только если ваши строки не содержат пробелов. В противном случае вы также разделите эти строки. – phillyslick

+1

@BenPolinsky, так как вы сообщили, что решение 'join' будет разделять строки с пространством, но фильтр не будет. Спасибо за комментарий, я улучшил свой ответ. –

0

Для устранения пустышки после зачистки:

slist = map(lambda s: s and s.strip(), slist) 
slist = filter(None, slist) 

Некоторых PROs:

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

    def f1(slist): 
        slist = [s and s.strip() for s in slist] 
        return list(filter(None, slist)) 
    
    def f2(slist): 
        slist = [s and s.strip() for s in slist] 
        return [s for s in slist if s] 
    
    
    def f3(slist): 
        slist = map(lambda s: s and s.strip(), slist) 
        return list(filter(None, slist)) 
    
    def f4(slist): 
        slist = map(lambda s: s and s.strip(), slist) 
        return [s for s in slist if s] 
    
    %timeit f1(words) 
    10000 loops, best of 3: 106 µs per loop 
    
    %timeit f2(words) 
    10000 loops, best of 3: 126 µs per loop 
    
    %timeit f3(words) 
    10000 loops, best of 3: 165 µs per loop 
    
    %timeit f4(words) 
    10000 loops, best of 3: 169 µs per loop 
    
0

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

[ «привет мир», «», «», «привет»] то, что вы можете [ «привет мир», «привет»]

первой обрезки список до конвертировать любой тип белого пространства пустой строки:

space_to_empty = [x.strip() for x in _text_list] 

затем удалить пустую строку из них список

space_clean_list = [x for x in space_to_empty if x is not ""] 
Смежные вопросы