2017-01-24 3 views
6

Я часто нужно отобразить список функций (процессоры) до нескольких массивов (каналов) данных с плавающей точкой), так что я написал вспомогательную функцию ...Картирования массива функций над массивом в Javascript

const mapMany = function(processors, channels){ 
    processors.forEach(function(processor){ 
    channels = channels.map((channel) => channel.map(processor)); 
    }); 
    return channels; 
}; 

Это читает ОК (по крайней мере, для меня!), Но сопоставление массива функций над другим массивом кажется таким общим, что я не могу не задаться вопросом, действительно ли это «вещь», то есть есть ли лучшее/встроенное/канонический способ реализации этой функциональности типа «Карта много» и если да, то каково ее собственное имя?

ответ

5

Да, есть лучший подход для реализации этого. Не используйте forEach!

function mapMany(processors, channels) { 
    return processors.reduce((channels, processor) => 
     channels.map(channel => channel.map(processor)) 
    , channels); 
} 

Но нет, для этого нет никакого встроенного или канонического названия. Это довольно специфическая функция, которая, однако, может быть тривиально составлена ​​из стандартных строительных блоков.

+0

Спасибо. Я думал, что я уже пробовал это, но оказалось, что я прошел, уменьшив его параметры, не так! – technicalbloke

1

Итак, как Берги указывает, что просто уменьшить я искал, разделив его на две функции делает его гораздо яснее ...

const applySingleProcessor = function(channels, processor){ 
    return channels.map(channel => channel.map(processor)); 
}; 

const applyMultipleProcessors = function(processors, channels) { 
    return processors.reduce(applySingleProcessor, channels); 
}; 

яй простота!

4

Я думаю, вы ищете compose. Это выглядит примерно так:

const compose = function (...fns) { 
    const rest = fns.reverse(); 
    const first = rest.shift(); 
    return function (...args) { 
     return rest.reduce((acc, f)=>f.call(this, acc), first.apply(this, args)); 
    }; 
}; 

Теперь вы можете сочинить такие функции, как это:

const stringDouble = compose(String, x=>x*2); 
stringDouble("44"); //==> "88" 

["22","33","44"].map(stringDouble); 
//=> ["44", "66", "88"] 

И в вашем случае вы можете написать функцию, как это:

const mapMany = function(processors, channels){ 
    // compose iterates from last to first so i apply reverse 
    const fun = compose.apply(undefined, processors.reverse()); 
    return channels.map(fun); 
}; 

Преимущество над ваш собственный код и другой ответ, используя reduce, заключается в том, что в этом процессе не производится массивы processors.length, а только один.

Есть библиотеки, которые поставляет compose. Это общая функция в функциональном программировании.

Другие функции отображения, такие как функции в подменю, позволяют вам установить this. Тогда методы класса будут работать, поскольку я передаю this основным функциям.

+0

'map (f). map (g) = map (f. g) '- важный и полезный идентификатор. – phg

+0

Спасибо. Это выглядит прекрасно. Исходя из десятилетий императивного кодирования, мне может потребоваться некоторое время, чтобы понять это, но я буду смотреть на него, пока не буду! – technicalbloke

+0

@technicalbloke Это не так сложно. В основном 'compose (a, b, c)' совпадает с '(... args) => a (b (c (... args))), поэтому он более общий. – Sylwester

0

Хотя я бы обычно использовал .reduce() как @Bergi, просто для разнообразия здесь просто рекурсивное решение .map() без .reduce();

var channels = [[1,2,3,4],[5,6,7,8], [857,1453,1881,1071]], 
 
    processors = [x => x+1, x => x*x, x => Math.sqrt(x), x => x-1], 
 
    mapMany = (processors, channels) => processors.length ? (channels = channels.map(c => c.map(processors[0])), 
 
                   mapMany(processors.slice(1),channels)) 
 
                  : channels; 
 
console.log(mapMany(processors,channels));

Смежные вопросы