2015-01-19 3 views
0

Я знаю, что функция .reduce в Javascript имеет понятие previous и current переменные «встроенный», так сказать, в его определении. Поэтому мне очень интересно, почему это не работает:Можно написать функцию bigram (или ngram), используя сокращение в Javascript?

var bigrams = [0, 1, 2, 3, 4].reduce(function(previous, current) { 
    return [previous, current] 
}); 

Я не думаю, что означает, что я думаю, что это значит, потому что теперь bigrams содержит:

[[[[0,1],2],3],4] 

Когда я хотел:

[[0,1],[1,2],[2,3],[3,4]] 

Я думаю, это связано с тем, что результат должен выталкиваться в accumlator (который, возможно, следует быть пустой массив, что-то вроде: arr.reduce(/*magic*/, [])

  • Должен ли я использовать .reduce для этого?
  • Если да, есть ли другой «функциональный» способ сделать это?
  • Как избежать этого поведения вложенности?
+0

Это функция * reduce * (* fold *), где 'previous' является * аккумулятором * (и не должен называться' previous'), а не функцией карты, имеющей доступ к ее предыдущему элементу. – Bergi

ответ

4

Принцип уменьшения работы заключается в том, что вывод одного вызова используется как вход для следующего вызова. Если мы называем вашу функцию f, ваш вызов эквивалентен:

f(f(f(f(0, 1), 2), 3), 4) 

Другими словами, previous не означает, что «предыдущий элемент в исходном массиве», это означает, что «результат предыдущего вызова функции» ,

reduce не является отличным выбором для этой задачи, поскольку, как следует из его названия, он нацелен на , уменьшая массив до одного значения. Один «функциональный» способ сделать это - использовать zip и закрепить массив со своим хвостом (все, кроме первого элемента), как показано в this Haskell example. Однако Javascript не имеет встроенной функции zip. Использование второго zip реализации от this answer:

function zip() { 
    var args = [].slice.call(arguments); 
    var shortest = args.length==0 ? [] : args.reduce(function(a,b){ 
     return a.length<b.length ? a : b 
    }); 

    return shortest.map(function(_,i){ 
     return args.map(function(array){return array[i]}) 
    }); 
} 

Вы можете сделать:

var x = [0, 1, 2, 3, 4] 
zip(x, x.slice(1)) 

Однако в JavaScript, я думаю, что большинство людей, вероятно, просто делать это итеративно, как и в ответах на this question.