Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to implement a js version of Haskell's unzip in a purely functional fashion?

I'm implementing a javascript ray-casting point-in-polygon algorithm in a purely functional fashion (no particular reason behind it).

I got stuck as i needed to get two arrays from a 2-dimentional array (replicating a list of tuples); something akin to Haskell's unzip.

Is it possible, starting from something like [[a,b],[c,d],[e,f]] to obtain [[a,c,e],[b,d,f]] without using procedural-style iterators?

(I know it's a trivial question, and I could just implement the function procedurally and then forget about it, but I was curious to know if there was a solution)


EDIT: To clarify, I know how to implement zip and unzip: I was wondering wether it might be possible to implement them without for loops and variable reassignments.

like image 399
cbrandolino Avatar asked Dec 15 '11 11:12

cbrandolino


1 Answers

Your unzip is just a zip but with multiple arguments. The only reason most people don't just use the same function is that most of the time zip receives a variadic list of arguments instead of a array so you need to unpack things with apply in the unzip function.

In Dojo, the library I am using, they implement zip and unzip as

unzip: function(/*Array*/ a){
    // summary: similar to dojox.lang.functional.zip(), but takes
    // a single array of arrays as the input.
    // description: This function is similar to dojox.lang.functional.zip()
    // and can be used to unzip objects packed by
    // dojox.lang.functional.zip(). It is here mostly to provide
    // a short-cut for the different method signature.

    return df.zip.apply(null, a);
}

zip: function(){
    // summary: returns an array of arrays, where the i-th array
    // contains the i-th element from each of the argument arrays.
    // description: This is the venerable zip combiner (for example,
    //    see Python documentation for general details). The returned
    //    array is truncated to match the length of the shortest input
    //    array.
    var n = arguments[0].length,
        m = arguments.length,
        i = 1,
        t = new Array(n),
        j,
        p;
    for(; i < m; n = Math.min(n, arguments[i++].length));
    for(i = 0; i < n; ++i){
        p = new Array(m);
        for(j = 0; j < m; p[j] = arguments[j][i], ++j);
        t[i] = p;
    }
    return t;
},

Note that zip receives multiple arguments so it is more like the Python zip and less like the Haskell one.


It should not be hard to conver this code to a "purely functional" style without variable assignments. Your existing code should already be handling the job of the first two fors in the example I posted (truncating the zip at the minimum length and iterating through the indices of one of the lists). All that is left is doing a similar thing for the third for - collecting the i-th value from a list of lists instead of collecting two values from two lists.

like image 180
hugomg Avatar answered Nov 15 '22 15:11

hugomg