user3238319
user3238319

Reputation: 51

Remove empty strings from tuples inside a list

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

Answers (2)

aychedee
aychedee

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

jayelm
jayelm

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 ints.

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

Related Questions