The zip() function in Python is a convenient mechanism for iterating over multiple “iterables” in parallel. Looping over lists is a common scenario.
Here is the output generated by the above code:
Common Lisp does not have such a feature built into the language or as part of the standard library. Of course, we have the expressive “loop” construct that allows us to iterate over multiple lists, etc. Here is an example that traverses multiple lists:
It is not difficult to program the zip() functionality in Lisp. In this article, I will show two ways to do this. For the sake of brevity, I am going to focus on lists as arguments to zip().
Using Function Closure
Our first implementation takes advantage of Lisp’s “closure”, where we return an anonymous function from a function. The anonymous function stores its state in the enclosing function’s variables. Here is the code:
The zip() function takes multiple lists as its arguments and returns a function that captures this state. Every time this function is called, it will return the next sequence from the list. For convenience and readability, I have also defined the next() function (as a macro) that returns the next element. It returns “nil” when the entire collection has been traversed.
The following shows an interactive session that uses the zip() function:
Note that the function correctly handles the case when not all lists are of the same size.
Using “struct” Abstraction
Yet another (in my view, better) approach is to wrap the zip() functionality around a class/struct. I have chosen struct because that is sufficient for our case. Here is the code:
Our struct contains just one instance variable called “elements” to keep track of the supplied collection. The main zip() method calls the constructor to instantiate a new object. As earlier, the next() method returns the next set of elements and return “nil” when the collection is fully traversed. I have also defined two convenience methods size() and remaining(). The former returns the number of pending items and the latter returns all remaining items from the sequence.
The following shows its usage:
It is possible to extend the implementation to cover other collections such as arrays, dictionaries, etc.
I have tested this implementation in LispWorks Enterprise 8.0.1, 64 bit edition on Windows 10. Here is the source code.
Have a nice week!
Zip is just called “map” in lisp languages: http://clhs.lisp.se/Body/f_map.htm
It’d be remiss for the lisp family to lack a higher order function to process multiple lists in parallel.
Eg in your first example, in “Racket” (I’m sure it’s very similar in lisp):
”
(map
(curry format “The elements are: ~a, ~a, and ~a.”)
‘(10 20 30)
‘(a b c)
‘(good better best))
”
There is one caveat: it requires all the input lists to be the same length. However, it’d be interesting to see the python version be more polymorphic like lisps map, and also to see lisps map accept lists of different lengths.