使用 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'}}}
最近我发现自己在我的应用程序中越来越多地使用关联数组(或 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'}}}