Today I had an interview and I was asked to print a list of list into one single list without using any for or while loop but you can use other built in function.
Here is the list:
>>> myList = [[[1,2,3],[4,5],[6,7,8,9]]]
>>> myList
[[[1, 2, 3], [4, 5], [6, 7, 8, 9]]]
>>>
The output will be [1, 2, 3, 4, 5, 6, 7, 8, 9]
.
Any idea how to go about this?
Three options:
You could sum the nested lists; sum()
takes a second argument, a starting value, set that to an empty list:
>>> sum(myList[0], [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
This works because sum()
is essentially implemented as a loop:
def sum(values, start=0):
total = start
for value in values:
total += value
return total
which works with list concatenation, provided the start value is a list object itself. 0 + [1, 2, 3]
would not work, but [] + [1, 2, 3]
works just fine.
You could use reduce()
with operator.add()
, which is essentially the same as sum()
, minus the requirement to give a start value:
from operator import add
reduce(add, myList[0])
operator.add()
could be replaced with lambda a, b: a + b
or with list.__add__
if imports are to be avoided at all cost.
As the nested input list grows, operator.iadd()
(in-place add, for lists the equivalent of list.extend()
) will rapidly become a faster option:
from operator import iadd
reduce(add, myList[0], [])
but this does need an empty list to start with.
You could chain the lists using itertools.chain.from_iterable()
:
>>> from itertools import chain
>>> list(chain.from_iterable(myList[0]))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
All three solutions require that you use indexing to remove the outermost list, although you can also pass the one element in myList
as a single argument to chain.from_iterable()
with list(chain.from_iterable(*myList))
as well.
Of these options, reduce(add, ...)
is the fastest:
>>> timeit.timeit("sum(myList[0], [])", 'from __main__ import myList')
1.2761731147766113
>>> timeit.timeit("reduce(add, myList[0])", 'from __main__ import myList; from operator import add')
1.0545191764831543
>>> timeit.timeit("reduce(lambda a, b: a.extend(b) or a, myList[0], [])", 'from __main__ import myList')
2.225532054901123
>>> timeit.timeit("list(chain.from_iterable(myList[0]))", 'from __main__ import myList; from itertools import chain')
2.0208170413970947
and comparing iadd
versus add
:
>>> timeit.timeit("reduce(add, myList[0])", 'from __main__ import myList; from operator import add')
0.9298770427703857
>>> timeit.timeit("reduce(iadd, myList[0], [])", 'from __main__ import myList; from operator import iadd')
1.178157091140747
>>> timeit.timeit("reduce(add, myListDoubled)", 'from __main__ import myList; myListDoubled = myList[0] + myList[0]; from operator import add')
2.3597090244293213
>>> timeit.timeit("reduce(iadd, myListDoubled, [])", 'from __main__ import myList; myListDoubled = myList[0] + myList[0]; from operator import iadd')
1.730151891708374
You could use recursion to avoid using a loop, to make this work for arbitrarily nested lists:
def flatten(lst):
try:
return flatten(sum(lst, []))
except TypeError:
return lst
Demo:
>>> flatten(myList)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> flatten(myList + myList)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9]
If we assume no imports allowed and that we are still on 2.7.x,
reduce(lambda x,y:x+y,*myList)
A quick search show that this question, making a flat list out of lists, has been analyzed in depth: Making a flat list out of list of lists in Python and although in that thread there is no restriction on what functions you can use, they answer goes into great detail about the time complexity of using different methods. This is quite important, as it could be the follow up question in an interview.
myList = [[[1,2,3],[4,5],[6,7,8,9]]]
sum(myList[0], [])
Output
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Use itertools.chain.from_iterable
:
In [34]: from itertools import chain
In [35]: list(chain.from_iterable(myList[0]))
Out[35]: [1, 2, 3, 4, 5, 6, 7, 8, 9]
try this
import itertools
list(itertools.chain(*mylist))