高阶reduce()函数

3
我希望将传递到我的数组reduce()函数的函数抽象化,使该函数成为通用的“数组最大值约简器”。为了实现这一点,我想在reduce()参数中传入不同的特定函数,以便指定比较条件。在我的示例中,这些是以下行:

return players.reduce(topPlayerReducer, players[0], getThreePointerPercentage);

return players.reduce(topPlayerReducer, players[0], getReboundNumber);

其中topPlayerReducer是传递给reduce()的通用函数,基于某些标准找到数组中最大的项。我的标准是第三个参数。如何合并我的特定比较函数(getThreePointerPercentage和getReboundNumber)以保持这种抽象水平?目前,我收到fn不是topPlayerReducer函数的错误。我对此并不感到惊讶,因为我的其他函数不在作用域内。我还尝试过执行以下操作:

var reboundReducer = topPlayerReducer.bind(getReboundNumber);

return gameInfo.players.reduce(reboundReducer, players[0]);}

但我遇到了相同的错误。

我意识到可以通过创建两个不同的reduce()函数来实现结果,但这并不能满足我的需求。我想知道是否有其他方法可以实现。

function getGuardWithMostThreePointers(gameInfo){
    return players.reduce(topPlayerReducer, players[0], getThreePointerPercentage);
}

function getPlayerWithMostRebounds(gameInfo){
    return players.reduce(topPlayerReducer, players[0], getReboundNumber);
}

function topPlayerReducer(topPlayer, currentPlayer, fn){
    if (fn(currentPlayer) > fn(topPlayer)){
        return currentPlayer;
    } else {
        return topRebounder;
    }
}

function getReboundNumber(player){
    return parseInt(player.rebounds_offensive) + parseInt(player.rebounds_defensive);
}

function getThreePointerPercentage(player){
    return parseInt(player.three_pointers_made) / parseInt(player.three_pointers_attempted);
}
1个回答

5
我会这样做:
更改topPlayerReducer的实现,使其返回一个比较两个玩家而不是比较玩家本身的函数:
function topPlayerReducer(fn){
    return function(topPlayer, currentPlayer) {
        if (fn(currentPlayer) > fn(topPlayer)){
            return currentPlayer;
        } else {
            return topPlayer;
        }
    }
}

然后您可以像这样调用reduce:

return pointGuards.reduce(topPlayerReducer(getThreePointerPercentage), pointGuards[0]);

或者

return gameInfo.players.reduce(topPlayerReducer(getReboundNumber), gameInfo.players[0]);

这样,您可以在每次调用reduce时传入一个自定义函数,只需首先将其包装在topPlayerReducer中。我认为这就是您试图通过bind实现的目标。
FYI:我认为您从bind中寻找的是称为部分应用的东西,其中您需要使用具有多个参数的函数,提供其中一些但不是全部参数,并获得一个期望剩余参数的函数。 您可以使用bind来完成此操作,但您必须记住:
  1. 绑定需要一个额外的参数,该参数绑定到函数内的this
  2. 您要“预加载”的参数将从左侧填充。
所以,如果您进行了以下更改,则可以尝试使用bind:
// Make fn the leftmost parameter
function topPlayerReducer(fn, topPlayer, currentPlayer){
    if (fn(currentPlayer) > fn(topPlayer)){
        return currentPlayer;
    } else {
        return topRebounder;
    }
}

// Add an extra 'null' argument to be bound to the `this` variable
return players.reduce(topPlayerReducer.bind(null, getReboundNumber), players[0])

依我看,这种情况下bind版本只会使代码变得混乱。但是当你的函数使用了this关键字,需要改变它的值时,bind就非常有用了。

成功了!它的工作原理有点难以置信,但我想我明白了。 - db2791
很棒。基本上,通过新的实现,每次调用 topPlayerReducer 都会返回一个全新的函数,该函数接受两个球员并返回满足条件的那个球员。通过这种方式创建的函数与直接定义的函数完全相同,因此您可以将其传递到 reduce 等函数中。如果您想更深入地了解它,请尝试对 topPlayerReducer 进行一些调整:在命令行/控制台中调用 var foo = topPlayerReducer(someFunc)。然后,您可以查看 foo 是什么,尝试使用一些参数调用它等。 - Peter

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