result
is a list of numbers:
result = [\'0\',\'5\',\'0\',\'1\']
I want to remove the leading zero, using the following expression:
This is what you've used!
>>> result = ['0','5','0','1']
>>> result[next((i for i, x in enumerate(result) if x != 0), len(result)):] or [0]
['0', '5', '0', '1']
Lets break down your list comprehension!
[i for i,x in enumarate(result)]
unpacks the enumerate(result)
as i and x. That is,
>>> enumerate(result)
<enumerate object at 0x7fc81d12bdc0>
>>> list(enumerate(result))
[(0, '0'), (1, '5'), (2, '0'), (3, '1')]
>>> for i,x in enumerate(result):
... print i,x
...
0 0
1 5
2 0
3 1
Filtering the results with non zero values,
>>> [i for i, x in enumerate(result) if x != 0]
[0, 1, 2, 3]
Now see the difference in comparing a string and an integer with x
>>> [i for i, x in enumerate(result) if x != '0'] #list comprehension
[1, 3]
>>> len(result)
4
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.
That is,
>>> next([i for i, x in enumerate(result) if x != 0], len(result)) # next takes first argument as iterator, in this example we've given a list, so exception is raised
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: list object is not an iterator
>>> next((i for i, x in enumerate(result) if x != '0'), len(result)) #comparing with string '0'
1
Now, we've got the first index of the list that has non zero values(lets have it as nzindex).
With that index, we do string slicing to get all the elements after the result[nzindex:]
This will return all elements after the index till the end.
>>> result[next((i for i, x in enumerate(result) if x != '0'), len(result)):]
['5', '0', '1']
If the string slicing returns an empty list(falsey result), the default value result[0] is returned!
>>> result = ['0']
>>> result[next((i for i, x in enumerate(result) if x != '0'), len(result)):] or result[0]
['0']
With that said if you want to remove all the zeros in the list,
>>> result = ['0','5','0','1']
>>> [x for i,x in enumerate(result) if x!='0']
['5', '1']
and if you want to remove only the leading zeros, a more efficient way would be,
>>> next(i for i,x in enumerate(result) if x!='0')
1
>>> result[next(i for i,x in enumerate(result) if x!='0'):]
['5', '0', '1']
The expression looks for the first non-zero in the list, returning the remaining list. More detail at the bottom.
ANALYSIS
However, you have characters: there is no integer 0
in your list. Therefore, the expression merely returns the original list.
SOLUTION
If you want it to work on characters, simply include the quotation marks required:
result[next((i for i, x in enumerate(result) if x != '0'), len(result)):] or ['0']
This give you:
Original code:
>>> result = ['0','5','0','1']
>>> result[next((i for i, x in enumerate(result) if x != 0), len(result)):] or [0]
['0', '5', '0', '1']
Adapted to strings / characters:
>>> result[next((i for i, x in enumerate(result) if x != '0'), len(result)):] or ['0']
['5', '0', '1']
>>> result = ['0','0','5','0','1']
>>> result[next((i for i, x in enumerate(result) if x != '0'), len(result)):] or ['0']
['5', '0', '1']
>>> result = ['7', '0','0','5','0','1']
>>> result[next((i for i, x in enumerate(result) if x != '0'), len(result)):] or ['0']
['7', '0', '0', '5', '0', '1']
EXPRESSION LOGIC
The critical clauses are in the deepest part of the comprehension:
(i for
i, x in enumerate(result)
if x != '0')
In the enumerate
clause, i, x
iterates through the list indices and its contents: (0, '0')
, (1, '5')
, etc.
The if
checks for zero characters; it filters out all zeroes. The i for
part doesn't get any i
value until the inner clause finds a non-zero.
At that point, the outer next
operator takes over: it takes the first index of a non-zero and returns that to the slice operator (note that colon at the end), which returns the remainder of the list.
As pault
already mentioned, the len
at the end is the default value: if your zero filter disqualifies the entire list (all zeroes), then the comprehension returns len(result)
to next
. This mean that next
will return the list length, and your result
slicing returns an empty list. Now your or expression has a "Falsy" value in the first operand; it returns the second operand, the list ['0']
.