Boris P
Boris P

Reputation: 23

multiple iterators for map() function in python?

I know there's a way to have the python map function execute for multiple iterators in one command, but I keep getting syntax or valueErrors, or if it does compile it just overwrites previous iterations or gives the wrong answer. What am I doing wrong?

num = ["1","2","3"]
num2 =["4","5","6"]
num3 = ["7","8","9"]

j = list(map(lambda x, y, z: int(x) and int(y) and int(z), num, num2, num3))
print(j)   #[7, 8, 9]
print(reduce(lambda x, y: x+y, j))   #24

The goal is to have all numbers across multiple lists mapped from string to integer into one big list, then summed using reduce()

j should come out to [1,2,3,4,5,6,7,8,9] all ints

the reduce should sum it to 45

update: this way doesnt work either

num = ["1","2","3"]
num2 =["4","5","6"]
num3 = ["7","8","9"]

j = list(map(lambda x, y, z: int(x+y+z), num, num2, num3))
print(j)  #[147, 258, 369]
print(reduce(lambda x, y: x+y, j)) #774

Upvotes: 2

Views: 4022

Answers (2)

Code-Apprentice
Code-Apprentice

Reputation: 83527

Since you want to iterate over the elements of each list as one long list, it is easiest to just concatenate them:

nums = map(int, num + num2 + num3)

Upvotes: 0

MSeifert
MSeifert

Reputation: 152647

Map with multiple iterators:

Given your desired intermediate output I'd say that map isn't the right tool to get a j containing the integers 1-9.

That's because map with multiple iterators goes through the iterators simultaneously:

enter image description here

It doesn't repeat, that's just because it's a gif file.

The problem(s) in your approaches:

In the first iteration it will return "1", "4", "7" (the first elements of each iterable) the next iteration will return "2", "5", "8" and the last iteration "3", "6", "9".

On each of these returns it will apply the function, in your first example in the first iteration that's

int("1") and int("4") and int("7")

which evaluates to 7 because that's the last truthy value of the chained ands:

>>> int("1") and int("4") and int("7")
7

That also explains why the result is 24 because the results of the other iterations are 8 and 9:

>>> int("2") and int("5") and int("8")
8
>>> int("3") and int("6") and int("9")
9

>>> 7 + 8 + 9
24

In your second example you added the strings (which concatenates the strings) and then converted it to an integer:

>>> "1" + "4" + "7"
"147"
>>> int("147")
147

The solution:

So, you need the addition from your second approach but apply the int to each variable like you did in the first example:

j = list(map(lambda x, y, z: int(x)+int(y)+int(z), num, num2, num3))

A better solution:

But for that problem I would probably use a different approach, especially if you want the "desired" j.

To get that you need to chain the iterables:

import itertools
chained = itertools.chain(num, num2, num3)

Then convert all of them to integers:

chained_integers = map(int, chained)

This chained_integers is the iterator-equivalent to the [1, 2, 3, 4, 5, 6, 7, 8, 9] list you wanted as j. You could also use chained_integers = list(map(int, chained)) and print the chained_integers before proceeding if you want to double-check that.

And finally to reduce it I would actually use the built-in sum function:

reduced = sum(chained_integers)  # or "reduce(lambda x, y: x+y, chained_integers)"

Or the one-line-version:

sum(map(int, itertools.chain(num, num2, num3)))

An alternative solution using a comprehension instead of map:

Even simpler would be a comprehension (in this case I used a generator expression) instead of the map:

reduced = sum(int(v) for v in itertools.chain(num, num2, num3))

An alternative solution using a generator function:

That's pretty short and easy to understand but I would like to present another example of how to do it using your own generator function:

def chain_as_ints(*iterables):
    for iterable in iterables:
        for item in iterable:
            yield int(item)

And you could use it like this:

sum(chain_as_ints(num, num2, num3))

In this case a generator function is not really necessary (and probably not advisable given the alternatives) I just wanted to mention it for completeness.

Upvotes: 5

Related Questions