简体   繁体   中英

Additional condition in Python list comprehension

How would you delete all starting empty items form a list using list comprehension without deleting empty elements in the middle of list. This is an example:

desc = []
desc.append('')
desc.append('')
desc.append('')
desc.append('line 1')
desc.append('line 2')
desc.append('')
desc.append('')
desc.append('line 3')
filtered = [x for x in desc if x]
filtered
['line 1', 'line 2', 'line 3']

Here is a simple list comprehension that delete all empty items:

filtered = [x for x in desc if x != '']

What I am trying to achieve using list comprehension is something similar to this:

for i in enumerate(desc):
    if desc[0].strip() == '':
        desc.pop(0)

Use itertools.dropwhile :

>>> from itertools import dropwhile

>>> lines = ['', '', 'line1', 'line2', '', '']
>>> list(dropwhile(lambda line: not line, lines))
['line1', 'line2', '', '']

Alternatively to the lambda, you could use operator.not_ , as @JonClements suggests:

>>> from operator import not_

>>> list(dropwhile(not_, lines))
['line1', 'line2', '', '']
>>> desc = ['', '', '  ', 'line 1', 'line 2', '', '', 'line 3']
>>> filtered = next(desc[i:] for i in range(len(desc)) if desc[i].strip())
>>> filtered
['line 1', 'line 2', '', '', 'line 3']

The built-in function next will only iterate till it finds non empty element in desc list. As soon it finds an element it will stop iteration and will return list from that element till the end instead of iterating whole desc list .

>>> help(next)
Help on built-in function next in module __builtin__:

next(...)
    next(iterator[, default])

    Return the next item from the iterator. If default is given and the iterator
    is exhausted, it is returned instead of raising StopIteration.

Other solutions are good. If list comprehension is not necessary then maybe you can try this single line method,

>>> desc
['', '', '', 'line 1', 'line 2', '', '', 'line 3']
>>> 
>>> ';'.join(desc).lstrip(';').split(';')
['line 1', 'line 2', '', '', 'line 3']
>>> 

Step 1 - Join all elements of the list by some delimiter

>>> x = ';'.join(desc)
';;;line 1;line 2;;;line 3'

Step 2 - Strip delimiters from the starting of the string

>>> x = x.lstrip(';')
'line 1;line 2;;;line 3'

Step 3 - Split the string on delimiter to get the output

>>> x.split(';')
['line 1', 'line 2', '', '', 'line 3']

A list comprehension is a nice way to write the creation of a result list only when the decision of which elements to include depend on properties of each sigle element itself.

If the condition depends on other factors (eg the position in the result) then probably an explicit loop is more readable instead (and readability is the main point of list comprehensions).

Examples of good use:

  • all even numbers of a list
  • all objects with a size bigger than a certain amount
  • all not empty elements

Examples that don't fit well the comprehension concept:

  • first five even number (NOT ok for a comprehension, the "first five" part doesn't depend on each single element)
  • removing empty elements at the beginning of a list (the condition depends on other elements)
  • unique elements, ie keeping only the first if an element appears multiple times (the decision about an element depends on previous decisions).

Of course you can try to abuse the comprehension to do things they were not designed for, but if the result code is less readable than just writing out the algorithm explicitly then there is no reason to do that.

May be you can just translate what you wrote into list comprehensions

filtered = desc[:]
crap = [filtered.pop(0) for i in filtered if filtered[0].strip()==""]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM