简体   繁体   中英

Flattening list in python

I have seen many posts regarding how to flatten a list in Python. But I was never able to understand how this is working: reduce(lambda x,y:x+y,*myList)

Could someone please explain, how this is working:

>>> myList = [[[1,2,3],[4,5],[6,7,8,9]]]
>>> reduce(lambda x,y:x+y,*myList)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>

Linked already posted :

How to print list of list into one single list in python without using any for or while loop?

Flattening a shallow list in Python

Flatten (an irregular) list of lists

If anybody thinks this is duplicate to other post, I'll remove it once I understood how it works.

Thanks.

What reduce does, in plain English, is that it takes two things:

  1. A function f that:
    1. Accepts exactly 2 arguments
    2. Returns a value computed using those two values
  2. An iterable iter (eg a list or str )

reduce computes the result of f(iter[0],iter[1]) (the first two items of the iterable), and keeps track of this value that was just computed (call it temp ). reduce then computes f(temp,iter[2]) and now keeps track of this new value. This process continues until every item in iter has been passed into f , and returns the final value computed.

The use of * in passing *myList into the reduce function is that it takes an iterable and turns it into multiple arguments. These two lines do the same thing:

myFunc(10,12)
myFunc(*[10,12])

In the case of myList , you're using a list that contains only exactly one list in it. For that reason, putting the * in front replaces myList with myList[0] .

Regarding compatibility, note that the reduce function works totally fine in Python 2, but in Python 3 you'll have to do this:

import functools
functools.reduce(some_iterable)

It is equivalent to :

def my_reduce(func, seq, default=None):
    it = iter(seq)
    # assign either the first item from the iterable to x or the default value
    # passed to my_reduce 
    x = next(it) if default is None else default
    #For each item in iterable, update x by appying the function on x and y
    for y in it:
        x  = func(x, y)
    return x
... 
>>> my_reduce(lambda a, b: a+b, *myList, default=[])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> my_reduce(lambda a, b: a+b, *myList)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> from operator import add
>>> my_reduce(add, *myList)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> my_reduce(lambda a, b: a+b, ['a', 'b', 'c', 'd'])
'abcd'

Docstring of reduce has a very good explanation:

reduce(...)
    reduce(function, sequence[, initial]) -> value

    Apply a function of two arguments cumulatively to the items of a sequence,
    from left to right, so as to reduce the sequence to a single value.
    For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
    ((((1+2)+3)+4)+5).  If initial is present, it is placed before the items
    of the sequence in the calculation, and serves as a default when the
    sequence is empty.

First of all, this is a very bad method. Just so you know.

reduce(f, [a, b, c, d]) runs

f(f(f(f(a, b), c), d)

Since f is lambda x,y:x+y , this is equivalent to

((a + b) + c) + d

For lists, a + b is the concatenation of the lists, so this joins each list.

This is slow because each step has to make a new list from scratch.

First, I don't know why it's wrapped in an array and then splatted ( * ). This will work the same way:

>>> myList = [[1,2,3],[4,5],[6,7,8,9]]
>>> reduce(lambda x,y:x+y,myList)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Explanation: reduce takes a method with two parameters - the accumulator and the element. It calls the method with each element and then sets the accumulator to the result of the lambda. Therefore, you're basically concatenating all the inner lists together.

Here's a step-by-step explanation:

  1. accumulator is initialized to myList[0] which is [1,2,3]
  2. lambda is called with [1,2,3] and [4,5] , it returns [1,2,3,4,5] , which is assigned to the accumulator
  3. lambda is called with [1,2,3,4,5] and [6,7,8,9] , it returns [1,2,3,4,5,6,7,8,9]
  4. no more elements left, so reduce returns that

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM