What is not working with my "map" usage?
Peter Otten
__peter__ at web.de
Sat Sep 22 15:11:00 EDT 2018
Victor via Python-list wrote:
> On Saturday, September 22, 2018 at 6:22:32 AM UTC-7, Peter Otten wrote:
>> Victor via Python-list wrote:
>>
>> > Let me use a different input args and display them below. Basically, I
>> > am
>> > hoping to add up all elements of each nested list. So at first it
>> > should
>> > start with [1,11,111] ==> 1+11+111 = 123. But instead, it appears to
>> > take
>> > the 1st element from each nested list to add up [1,2,3] = 6. How
>> > should
>> > it be corrected? Thx.
>>
>> I see three options. You can
>>
>> (1) use a list comprehension
>>
>> [add_all_elements(*sub) for sub in alist]
>>
>> (2) replace map() with itertools.starmap()
>>
>> list(itertools.starmap(add_all_elements, alist))
>>
>> (3) change your function's signature from add_all_elements(*args) to
>> add_all_elements(args), either by modifying it directly or by wrapping it
>> into another function
>>
>> list(map(lambda args: add_all_elements(*args), alist))
>>
>> (3a) My personal preference would be to change the signature and then use
>> the list comprehension
>>
>> def add_all_elements(args): ...
>> [add_all_elements(sub) for sub in alist]
>
> Hi Peter,
> Thank you for your suggested solutions. They all work. But I just want
> to know what is wrong with my doing:
>
> list(map(add_all_elements,*alist))
>
> Theoretically, each list element is passed to add_all_elements. And if my
> alist is [[1, 11, 111], [2, 22, 222], [3, 33, 333]], then the 1st list
> element must be this [1,11,111] passed as args into add_all_elements.
>
> In other words, the following should have happened:
>
>>>> add_all_elements (*[1,11,111])
That's not what happens. Try it with a function that passes through its
arguments unchanged:
>>> items = [[1, 11, 111], [2, 22, 222], [3, 33, 333]]
>>> list(map(lambda *args: args, *items))
[(1, 2, 3), (11, 22, 33), (111, 222, 333)]
The star before items is evaluated directly rather than magically passed on
to the call of add_all_elements.
map(f, *items)
is equivalent to
map(f, items[0], items[1], items[2])
which calls f with
f(items[0][0], items[1][0], items[2][0])
f(items[0][1], items[1][1], items[2][1])
f(items[0][2], items[1][2], items[2][2])
If you think of your list of lists as a matrix that matrix is effectively
transposed (x and y axis are swapped).
>>> list(map(lambda *args: sum(args), *items))
[6, 66, 666]
In principle you could transpose the matrix twice
>>> list(map(lambda *args: sum(args), *zip(*items)))
[123, 246, 369]
but that's not a very efficient approach.
Another gotcha to be aware of is that map() (and zip()) stop when the
shortest argument ends:
>>> list(map(lambda *args: sum(args), [], *items))
[]
>>> list(map(lambda *args: sum(args), [42], *items))
[48]
>>> list(map(lambda *args: sum(args), [42, 42], *items))
[48, 108]
>>> list(map(lambda *args: sum(args), [42, 42, 42, 42, 42], *items))
[48, 108, 708]
More information about the Python-list
mailing list