zipWith analogue in Python?

PythonHaskell

Python Problem Overview


What is the analogue of Haskell's zipWith function in Python?

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

Python Solutions


Solution 1 - Python

map()

map(operator.add, [1, 2, 3], [3, 2, 1])

Although a LC with zip() is usually used.

[x + y for (x, y) in zip([1, 2, 3], [3, 2, 1])]

Solution 2 - Python

You can create yours, if you wish, but in Python we mostly do

list_c = [ f(a,b) for (a,b) in zip(list_a,list_b) ] 

as Python is not inherently functional. It just happens to support a few convenience idioms.

Solution 3 - Python

You can use map:

>>> x = [1,2,3,4]
>>> y = [4,3,2,1]
>>> map(lambda a, b: a**b, x, y)
[1, 8, 9, 4]

Solution 4 - Python

A lazy zipWith with itertools:

import itertools

def zip_with(f, *coll):
    return itertools.starmap(f, itertools.izip(*coll))

This version generalizes the behaviour of zipWith with any number of iterables.

Solution 5 - Python

Generally as others have mentioned map and zip can help you replicate the functionality of zipWith as in Haskel.

Generally you can either apply a defined binary operator or some binary function on two list.An example to replace an Haskel zipWith with Python's map/zip

Input: zipWith (+) [1,2,3] [3,2,1] 
Output: [4,4,4] 

>>> map(operator.add,[1,2,3],[4,3,2])
[5, 5, 5]
>>> [operator.add(x,y) for x,y in zip([1,2,3],[4,3,2])]
[5, 5, 5]
>>> 

There are other variation of zipWith aka zipWith3, zipWith4 .... zipWith7. To replicate these functionalists you may want to use izip and imap instead of zip and map.

>>> [x for x in itertools.imap(lambda x,y,z:x**2+y**2-z**2,[1,2,3,4],[5,6,7,8],[9,10,11,12])]
>>> [x**2+y**2-z**2 for x,y,z in itertools.izip([1,2,3,4],[5,6,7,8],[9,10,11,12])]
[-55, -60, -63, -64] 

As you can see, you can operate of any number of list you desire and you can still use the same procedure.

Solution 6 - Python

I know this is an old question, but ...

It's already been said that the typical python way would be something like

results = [f(a, b) for a, b in zip(list1, list2)]

and so seeing a line like that in your code, most pythonistas will understand just fine.

There's also already been a (I think) purely lazy example shown:

import itertools

def zipWith(f, *args):
    return itertools.starmap(f, itertools.izip(*args))

but I believe that starmap returns an iterator, so you won't be able to index, or go through multiple times what that function will return.

If you're not particularly concerned with laziness and/or need to index or loop through your new list multiple times, this is probably as general purpose as you could get:

def zipWith(func, *lists):
    return [func(*args) for args in zip(*lists)]

Not that you couldn't do it with the lazy version, but you could also call that function like so if you've already built up your list of lists.

results = zipWith(func, *lists)

or just like normal like:

results = zipWith(func, list1, list2)

Somehow, that function call just looks simpler and easier to grok than the list comprehension version.


Looking at that, this looks strangely reminiscent of another helper function I often write:

def transpose(matrix):
    return zip(*matrix)

which could then be written like:

def transpose(matrix):
    return zipWith(lambda *x: x, *matrix)

Not really a better version, but I always find it interesting how when writing generic functions in a functional style, I often find myself going, "Oh. That's just a more general form of a function I've already written before."

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionYrogirgView Question on Stackoverflow
Solution 1 - PythonIgnacio Vazquez-AbramsView Answer on Stackoverflow
Solution 2 - PythondsignView Answer on Stackoverflow
Solution 3 - Pythonheinrich5991View Answer on Stackoverflow
Solution 4 - PythonTaurus OlsonView Answer on Stackoverflow
Solution 5 - PythonAbhijitView Answer on Stackoverflow
Solution 6 - PythoneverythingfunctionalView Answer on Stackoverflow