Что такое замена функционального стиля для этого цикла?

nums = [2 5 3 7]
result = []
result.push {x:nums[0]}
for n in nums.slice(1)
    result.push {n:n + result[-1].x}
log result
# [{x:2} {x:7} {x:10} {x:17}]

Это трудно выразить функционально с помощью функции map потому что каждый элемент зависит от предыдущего элемента. Какое правильное функциональное решение для этого алгоритма?

6 ответов

Самый простой способ, который я знаю, - избегать замыканий, грабящих производительность, переменных, дополнительных служебных функций и глобальных переменных:

result= [2, 5, 3, 7].map(function(a){ return { x: this[0]+=a }; }, [0]);

JS предоставляет редко используемый второй параметр.map() для хранения любого необходимого состояния между итерациями.

Наверное, проще не бывает, но кофе не знаешь, извини...

РЕДАКТИРОВАТЬ: взяли демо на двух языках (js+cs): http://pagedemos.com/maptranforms/

То, что вы описываете, это сканирование: складка, которая также возвращает промежуточные результаты. С помощью scan1 из prelude.ls:

nums = [2 5 3 7]
scan1 (+), nums |> map ((num) -> { x : num })
# => [{x: 2}, {x: 7}, {x: 10}, {x: 17}]

Если вам не нужны объекты внутри массива и вам нужны только дополнения с промежуточными результатами, вы можете вообще отказаться от операции map и просто написать:

scan1 (+), [2 5 3 7] # => [2, 7, 10, 17]

scan1 документация.

Вам нужно где-то хранить информацию о состоянии. Вот закрытие JavaScript, которое делает эту работу:

var nums = [2, 5, 3, 7];
var result = nums.map(
    (function() {
        var lastX = 0;
        return function(n) {
            return {x : (lastX += n)};
        }
     }())
);
// result is [{x:2} {x:7} {x:10} {x:17}]

dandavis ответ в coffeescript:

nums.map ((x)->{x: @[0] += x}), [0]

вариант, который может быть немного яснее

nums.map ((x)->{x: @accum += x}), {accum:0}

используя coffeescript понимание (и та же идея аккумулятора)

accum = 0; z = ({x: accum += i} for i in nums)

JavaScript

Держите текущий счетчик и просто добавляйте новый номер каждый раз:

var nums = [2,5,3,7];

var createObject = function(nums){ 
    var result = [],
        total = 0;

    for(var i = 0; i < nums.length; i++){
        total += nums[i]; 
        result.push({"x": total});
    }

    return result;
};

JSFIDDLE

map (-> {x:it}) <| (fold ((acc, a) -> acc ++ [a + ((last acc) ? 0)]), []) <| [2, 5, 3, 7]
Другие вопросы по тегам