使用 Ramba、下划线或普通 Javascript 构建关联数组的最佳方法?

Optimal way to build an associative array using Ramba, underscore or plain Javascript?

最近我发现自己在我的应用程序中越来越多地使用关联数组(或 hastables)(优点是查找速度、重复删除等)。

这是从我的应用程序中提取的典型代码 -

 var parent1 = { id: 5, name: 'parent 1'}, parent2  = { id: 10, name: 'parent 2'};
 var children = [{id: 1, parent: parent1}, {id: 2, parent: parent1}, {id: 3, parent: parent1}, {id: 4, parent: parent2}]

var addToHash = function (hashObj, child) {
    var parent = child.parent;
    hashObj[parent.id] = parent;
    return hashObj;
};

var uniqueParents = R.reduce(addToHash, {}, children);

目前我使用的是 Ramda 的 reduce 函数。

问题 - 是否有更好(更简洁)的方法来使用 Ramda、另一个第 3 方库或简单地使用普通香草 Javascript?

reduce(Ramda 的或 JavaScript 自己的)在这里不会给你带来任何好处,它只是增加了编写错误的机会(忘记 return hashObj) 并且我会主观地争论语义是关闭的。 reduce 用于当累加器 发生变化时 ,如对数组中的值求和的经典示例。

您可以通过给自己一个更适合手头工作的可重用函数来使其更简洁:

function buildHash(hash, array, callback, thisArg) {
    array.forEach(function(entry) {
        callback.call(thisArg, hash, entry);
    });
    return hash;
}

然后:

var addToHash = function(hash, child) {
    var parent = child.parent;
    hash[parent.id] = parent;
};
var uniqueParents = buildHash({}, children, addToHash);

或者作为 Array.prototype 扩展,您添加 Object.defineProperty 这样毫无戒心的 for-in 循环就不会被绊倒:

Object.defineProperty(Array.prototype, "buildHash", {
    value: function buildHash(hash, array, callback, thisArg) {
        array.forEach(function(entry) {
            callback.call(thisArg, hash, entry);
        });
        return hash;
    }
});

那么还是一样addToHash,只是调用更简洁:

var uniqueParents = children.buildHash({}, addToHash);

如果您使用 ES2015 的箭头函数,所有这些都会变得更加简洁。 :-)

一种可能:

R.pipe(
  R.map(prop('parent')),                //=> [parent1, parent1, parent1, parent2]
  R.uniq,                               //=> [parent1, parent2]
  R.map(parent => [parent.id, parent]), //=> [[5, parent1], [10, parent1]]
  R.fromPairs                           //=> {5: parent1, 10: parent2}
)(children); 
//=> {5: {id: 5, name: 'parent 1', 10: {id: 10, name: 'parent 2'}}}

请注意,如果您只需要 uniq parents 列表而不是 hashmap,则可以在管道中的第二个函数之后停止。

另一种选择,类似于您的选择,它只是将您的函数变成 returns 一个新的累加器而不是改变它的函数是:

var parentMap = R.reduce((acc, child) => R.assoc(child.parent.id, child.parent, acc), {});
parentMap(children); //=> {5: {id: 5, name: 'parent 1', 10: {id: 10, name: 'parent 2'}}}