58

I want to iterate through list of list.
I want to iterate through irregularly nested lists inside list also.
Can anyone let me know how can I do that?

x = [u'sam', [['Test', [['one', [], []]], [(u'file.txt', ['id', 1, 0])]], ['Test2', [], [(u'file2.txt', ['id', 1, 2])]]], []]
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
sam
  • 18,509
  • 24
  • 83
  • 116
  • 1
    Is there any system in the nesting of your list? What's the practical context of your iteration task, i.e. what are you doing with the elements in the list? Knowing this would help in providing tailored answers. – Oben Sonne Jun 14 '11 at 07:45
  • actually i just want to nest it – sam Jun 14 '11 at 07:51
  • 3
    possible duplicate of [Flatten (an irregular) list of lists in Python](http://stackoverflow.com/questions/2158395/flatten-an-irregular-list-of-lists-in-python) – Kimvais Jun 14 '11 at 07:53

11 Answers11

64

This traverse generator function can be used to iterate over all the values:

def traverse(o, tree_types=(list, tuple)):
    if isinstance(o, tree_types):
        for value in o:
            for subvalue in traverse(value, tree_types):
                yield subvalue
    else:
        yield o

data = [(1,1,(1,1,(1,"1"))),(1,1,1),(1,),1,(1,(1,("1",)))]
print list(traverse(data))
# prints [1, 1, 1, 1, 1, '1', 1, 1, 1, 1, 1, 1, 1, '1']

for value in traverse(data):
    print repr(value)
# prints
# 1
# 1
# 1
# 1
# 1
# '1'
# 1
# 1
# 1
# 1
# 1
# 1
# 1
# '1'
Jeremy
  • 1
  • 85
  • 340
  • 366
  • there is missing tree_types parameter in fourth line. – Liso Mar 10 '15 at 08:20
  • @Liso that parameter is optional, and given by default if left out – nmz787 Aug 07 '15 at 22:43
  • 2
    @nmz787 if you use non default parameter on top level then it will be forgotten on lower levels. Try to use list(traverse([1,2,3,set([4,5,6])],tree_types=(list,set))) with and without explicit calling tree_types in fourth line. – Liso Aug 09 '15 at 05:40
  • Why is the nested "for" required? When printing the leaves I found a single "for" works, but with "yield" it does not. – Abram Jun 02 '17 at 18:02
50

So wait, this is just a list-within-a-list?

The easiest way is probably just to use nested for loops:

>>> a = [[1, 3, 4], [2, 4, 4], [3, 4, 5]]
>>> a
[[1, 3, 4], [2, 4, 4], [3, 4, 5]]
>>> for list in a:
...     for number in list:
...         print number
...
1
3
4
2
4
4
3
4
5

Or is it something more complicated than that? Arbitrary nesting or something? Let us know if there's something else as well.

Also, for performance reasons, you might want to look at using list comprehensions to do this:

http://docs.python.org/tutorial/datastructures.html#nested-list-comprehensions

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
victorhooi
  • 16,775
  • 22
  • 90
  • 113
  • 1
    what if inner lists will be more? – sam Jun 14 '11 at 08:12
  • 1
    @sam Same pattern applies. Example: 'a = [[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]]] for list in a: for list in list: for number in list: print (number)' – user3624582 Aug 04 '14 at 07:19
  • 7
    The problem with this technique is that it doesn't allow for arbitrarily deep nests. At the time of writing the script you specify how deep each list should be, and that's that. – Magic_Matt_Man Dec 19 '14 at 10:42
21

This can also be achieved with itertools.chain.from_iterable which will flatten the consecutive iterables:

import itertools
for item in itertools.chain.from_iterable(iterables):
    # do something with item    
igniteflow
  • 8,404
  • 10
  • 38
  • 46
5

if you don't want recursion you could try:

x = [u'sam', [['Test', [['one', [], []]], [(u'file.txt', ['id', 1, 0])]], ['Test2', [], [(u'file2.txt', ['id', 1, 2])]]], []]
layer1=x
layer2=[]
while True:
    for i in layer1:
        if isinstance(i,list):
            for j in i:
                layer2.append(j)
        else:
            print i
    layer1[:]=layer2
    layer2=[]
    if len(layer1)==0:
        break

which gives:

sam
Test
Test2
(u'file.txt', ['id', 1, 0])
(u'file2.txt', ['id', 1, 2])
one

(note that it didn't look into the tuples for lists because the tuples aren't lists. You can add tuple to the "isinstance" method if you want to fix this)

Rusty Rob
  • 16,489
  • 8
  • 100
  • 116
4

Create a method to recursively iterate through nested lists. If the current element is an instance of list, then call the same method again. If not, print the current element. Here's an example:

data = [1,2,3,[4,[5,6,7,[8,9]]]]

def print_list(the_list):

    for each_item in the_list:
        if isinstance(each_item, list):
            print_list(each_item)
        else:
            print(each_item)

print_list(data)
swimfar
  • 147
  • 6
Akshay Sharma
  • 97
  • 1
  • 4
4

It sounds like you need to use recursion. Make a function to iterate through a list, and if it hits an item that is also a list, call itself to iterate on the member. Here's a link to something similar:

http://www.saltycrane.com/blog/2008/08/python-recursion-example-navigate-tree-data/

Codie CodeMonkey
  • 7,669
  • 2
  • 29
  • 45
  • If your list has arbitrary complexity, then you either have to use recursion, or simulate recursion by keeping a stack. You use the stack to push your "context" so that when you are done iterating your sub-list you can pop the stack to remember where you were. This works to an arbitrary depth without recursion, but it's more trouble than it's worth, and is essentially the same thing. – Codie CodeMonkey Jun 14 '11 at 08:12
4

If you wonder to get all values in the same list you can use the following code:

text = [u'sam', [['Test', [['one', [], []]], [(u'file.txt', ['id', 1, 0])]], ['Test2', [], [(u'file2.txt', ['id', 1, 2])]]], []]

def get_values(lVals):
    res = []
    for val in lVals:
        if type(val) not in [list, set, tuple]:
            res.append(val)
        else:
            res.extend(get_values(val))
    return res

get_values(text)
Artsiom Rudzenka
  • 27,895
  • 4
  • 34
  • 52
  • Please note this is probably not optimal for just iterating the list, because a new list holding all of the elements is created. That is why I like the answer with a generator more. – Jacek Konieczny Jun 14 '11 at 08:14
  • @Jacek Konieczny - sure you are right, i have posted this solution for those who are not familiar with generators. – Artsiom Rudzenka Jun 14 '11 at 08:19
4
x = [u'sam', [['Test', [['one', [], []]], [(u'file.txt', ['id', 1, 0])]], ['Test2', [], [(u'file2.txt', ['id', 1, 2])]]], []]
output = []

def lister(l):
    for item in l:
        if type(item) in [list, tuple, set]:
            lister(item)
        else:
            output.append(item)

lister(x)
Mp0int
  • 18,172
  • 15
  • 83
  • 114
2

two nested for loops?

 for a in x:
     print "--------------"
     for b in a:
             print b

It would help if you gave an example of what you want to do with the lists

Alftheo
  • 868
  • 7
  • 17
  • Exactly what I wanted to ask. What if there are more than 2 levels of nested list. This answer is a bound to many questions. – hlkstuv_23900 Dec 10 '14 at 06:43
1
# house list of lists
house = [["hallway", 11.25], ["kitchen", 18.0], ["living room", 20.0], 
         ["bedroom", 10.75], ["bathroom", 9.50]]
         
for key, y in house :
    print('The ' + key + ' is ' + str(y) + ' sqm ')
eddy
  • 11
  • 3
  • 1
    Your answer is valid in the context of your example¹, and it is quite simple which is good. Unfortunately, it won't work in the context of the question. _1 – And in any context where you know your iterable only contains 2-elements iterables._ – Faibbus Apr 29 '21 at 17:43
-1
mylist12 = [1,2,[3,4],[5,6,7],8]

print(dir(mylist12)) # iterable


for i in mylist12:
    if (isinstance(i,list)):
        for j in i:
            print(j)
    else:
            print(i)
Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
raghu
  • 1
  • 1