在Javascript中将一个函数数组映射到一个数组上

6

我经常需要将一系列函数(处理器)映射到多个float数据通道的数组中,因此我编写了一个辅助函数...

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

我觉得这篇文章读起来还不错,但是将一个函数数组映射到另一个数组似乎是一件非常通用的事情,我不禁想知道它是否已经成为“一种”方式,也就是说,是否有更好/内置/规范的实现“Map Many”类型功能的方法,如果有,它的正确名称是什么?

4个回答

5

是的,有更好的方法来实现这个功能。不要使用forEach

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

但是,没有内置的函数可以实现这个功能,也没有官方命名。这是一个非常特定的功能,但可以通过标准构建块轻松地组合实现。


谢谢。我以为我已经尝试过了,但事实证明我把reduce的参数传递顺序搞错了! - Roger Heathcote

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。这是函数式编程中常见的函数。
Underscore中的其他映射函数允许您设置this。然后类方法将像我一样将this传递给底层函数。

map(f) . map(g) = map(f . g) 是一个重要且有用的等式。 - phipsgabler
谢谢。看起来很不错。作为几十年命令式编程的从业者,可能需要我一些时间来理解它,但我会一直盯着它直到理解! - Roger Heathcote
@technicalbloke 这并不难。基本上,compose(a,b,c)(...args)=>a(b(c(...args)))是相同的,只是更加通用。 - Sylwester

1
因此,正如Bergi指出的那样,我只是在寻找reduce函数,将其拆分为两个函数使其更加清晰...
const applySingleProcessor = function(channels, processor){
  return channels.map( channel => channel.map(processor) );
};

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

耶!简洁明了!


0

虽然我通常会像@Bergi一样使用.reduce(),但为了多样性,这里提供一个简单的递归.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));


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接