Подтвердить что ты не робот

Можно ли реализовать js-версию Haskell unzip в чисто функциональном режиме?

Я реализую алгоритм point-in-polygon с использованием javascript-лучей в чисто функциональном режиме (без особой причины).

Я застрял, поскольку мне нужно было получить два массива из 2-мерного массива (реплицируя список кортежей); что-то похожее на Haskell unzip.

Возможно ли, начиная с чего-то вроде [[a,b],[c,d],[e,f]] получить [[a,c,e],[b,d,f]] без использования итераторов процедурного стиля?

(Я знаю, что это тривиальный вопрос, и я мог бы просто реализовать функцию процедурно, а затем забыть об этом, но мне было любопытно узнать, есть ли решение)


EDIT: для пояснения я знаю, как реализовать zip и unzip: мне было интересно, возможно ли реализовать их без циклов for и переменных переназначений.

4b9b3361

Ответ 1

Ваша распаковка - это просто zip, но с несколькими аргументами. Единственная причина, по которой большинство людей не просто использует одну и ту же функцию, - это то, что большую часть времени zip получает переменный список аргументов вместо массива, поэтому вам нужно распаковать вещи с помощью apply в функции распаковки.

В Dojo, библиотеке, которую я использую, они реализуют zip и unzip как

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;
},

Обратите внимание, что zip получает несколько аргументов, поэтому он больше похож на Python zip и меньше похож на Haskell.


Не следует превращать этот код в "чисто функциональный" стиль без назначения переменных. Ваш существующий код уже должен обрабатывать работу первых двух fors в приведенном выше примере (обрезание zip на минимальной длине и повторение по индексам одного из списков). Все, что осталось, делает аналогичную вещь для третьего для - сбора i-го значения из списка списков вместо сбора двух значений из двух списков.