Reputation: 51
Right now I have three lists that are generated from a RE findall function, and I am trying to remove some of the empty strings from the tuples inside the list. And the numbers should be converted to integer in the process too:
Got:[('', '', '1', '1')]
Expected: [(1, 1)]
Got: [('', '', '20', '500'), ('21', 'failed', '', '')]
Expected: [(20, 500), (21, 'failed')]
Got: [('3', 'failed', '', ''), ('', '', '48', '23'), ('', '', '96', '0')]
expected: [(3, 'failed'), (48, 23), (96, 0)]
Any ideas?
Upvotes: 5
Views: 7576
Reputation: 25609
How about this:
def sanitize(t):
for i in t:
try:
yield int(i)
except ValueError:
yield i
inputs = [('3', 'failed', '', ''), ('', '', '48', '23'), ('', '', '96', '0')]
map(tuple, map(sanitize, [filter(None, i) for i in inputs]))
Gives output of:
[(3, 'failed'), (48, 23), (96, 0)]
filter
is a function that operates on a sequence and returns only the "truthy" elements. Empty strings are falsy. Map is another function that takes a sequence and runs each element in that sequence through a given function. In this case the function sanitize
which converts a string to a int if it can or else just returns the string.
We are using yield
rather than return
in the sanitize
function as an easy way to return yet another sequence to the next map function. Alternatively we could build a list inside the function and return it.
Upvotes: 5
Reputation: 7678
A nested list comprehension with a tuple constructor:
>>> lst = [('', '', '20', '500'), ('21', 'failed', '', '')]
>>> [(tuple(int(x) if x.isdigit() else x for x in _ if x)) for _ in lst]
[(20, 500), (21, 'failed')]
For each tuple (_
) in lst
, construct a tuple
with a generator expression. The tuple constructor alone is below:
tuple(int(x) if x.isdigit() else x for x in _ if x)
Which seems confusing, but I'll break it down. For each string x
in tuple _
(which is a tuple in lst
), construct a tuple. if x
checks to see if the string is not empty. (If string x
is empty, x
is false.) if x
, the generator expression will produce either x
or int(x)
depending on whether x
in question is a digit in string form. (Trying to turn a non-numeric string into an integer will result in an exception.)
For each tuple _
in lst
, the generator creates a new, identical tuple, except the empty, false strings are filtered out and any digit strings are converted into int
s.
Above code is equivalent to:
new_lst = []
for _ in lst: # For each tuple in lst
for x in _: # For each string in tuple
temp_tuple = ()
if x: # Only add to tuple if string is not empty
if x.isdigit(): # If x is a digit in string form
temp_tuple += (int(x),) # Convert to int
else:
temp_tuple += (x,) # Keep string
new_lst.append(temp_tuple)
Upvotes: 8