Greedo
Greedo

Reputation: 5533

How to loop through a list of lists while preserving structure

I am trying to create a simple function to reformat items in a list then print them

This is simple enough for a list:

my_list = [1/3,7/11,2/5] #generate list of floats
formatted_list = ['%.2f' % elem for elem in my_list] #format to 2 d.p
print(formatted_list) #print re-formatted list

But I have a list of nested lists. To loop through each item of these I need to do something like in this answer. That then allows me to write say

my_list = [(1/3,1/4,1/5), (2/3,2/4,2/5), 3/3]
formatted_list = ['%.2f' % elem for elem in traverse(my_list)] #loop over unpacked list

However the major drawback of this, is that it no longer preserves the structure (the tuples within the list).

That is:

print(formatted_list)

returns

0.33, 0.25, 0.2, 0.66, 0.5, 0.4, 1.0
#I want (0.33, 0.25, 0.2), (0.66, 0.5, 0.4), 1.0

Is there a way of reformatting, or more generally iterating over items in an arbitrarily deep nested list, to return a list with the same structure as the original?

Upvotes: 1

Views: 898

Answers (2)

Stefan Pochmann
Stefan Pochmann

Reputation: 28596

This one supports arbitrary nesting of lists/tuples/sets of floats.

def myformat(x):
    return '%.2f' % x if isinstance(x, float) else type(x)(map(myformat, x))

Demo:

>>> myformat([(1/3, 1/4), [2/3, (2/4, {2/5})], 3/3])
[('0.33', '0.25'), ['0.67', ('0.50', {'0.40'})], '1.00']

Alternative implementation that also works for other types of numbers:

def myformat(x):
    try:
        return type(x)(map(myformat, x))
    except:
        return '%.2f' % x

Alternatively, the original version could use isinstance(x, numbers.Number).

Upvotes: 5

Bharath M Shetty
Bharath M Shetty

Reputation: 30605

Maybe a nested comprehension help i.e

formatted =  [tuple(['%.2f' % j for j in elem]) if isinstance(elem,tuple) else '%.2f' % elem for elem in my_list ]

Upvotes: 1

Related Questions