我正在寻找一种方法(在JavaScript中)将一组对象收集到多个数组中,其中每个数组包含某种类型的对象,并且数组作为值存储在关联数组中,其中键为类型。例如:
输入:
[<apple>, <cat>, <pear>, <mercedes>, <dog>, <ford>, <orange>]
输出:
{
'fruit': [<apple>, <pear>, <orange>],
'animal': [<cat>, <dog>],
'car': [<mercedes>, <ford>]
}
在ruby中,您可以执行以下操作:
things_by_type = {}
things.each do |thing|
(things_by_type[thing.type] ||= []) << thing
end
这很简洁。
在JavaScript中做同样的事情,简洁高效的好模式是什么?我可以做这样的事情,但它并不那么好:
var thing, things_by_type = {};
for (var i = 0; i < things.length; i++) {
thing = things[i];
if(things_by_type[thing.type]) {
things_by_type[thing.type].push(thing);
} else {
things_by_type[thing.type] = [thing];
}
}
答案 0 :(得分:1)
我不确定它是不是一个好的模式,但它与你的红宝石样本类似:
var things_by_type = {};
for (var i in things) {
var thing = things[i];
(things_by_type[thing.type] || (things_by_type[thing.type] = [])).push(thing);
}
如果你可以假设Javascript 1.6:
var things_by_type = {};
things.forEach(function(thing) {
(things_by_type[thing.type] || (things_by_type[thing.type] = [])).push(thing);
})
答案 1 :(得分:1)
在ruby中,您可以执行以下操作:
things_by_type = {} things.each do |thing| (things_by_type[thing.type] ||= []) << thing end
这很简洁。
实际上,你可以做得更好。
首先,Hash.new
接受一个块参数,每次引用一个不存在的键时都会调用该参数。您可以使用它来创建该密钥。这样你就可以摆脱块内的条件逻辑。
things_by_type = Hash.new {|h, k| h[k] = [] }
things.each do |thing|
things_by_type[thing.type] << thing
end
其次,你在这里所谓的fold
或reduce
:你将一个集合(对象数组)“折叠”或“缩减”成一个单独的值(哈希,令人困惑的也恰好是一个集合,但仍然是一个单一的价值。)
通常可以通过查找初始化某个变量的位置,然后遍历集合并在循环的每次迭代中操作该变量来轻松发现此模式。
Ruby通过Enumerable#reduce
方法内置折叠:
things.reduce(Hash.new {|h, k| h[k] = [] }) do |h, thing|
h.tap { h[thing.type] << thing }
end
但是你真正做什么,是通过其元素的type属性对数组进行分组,它也以Enumerable#group_by
的形式构建在Ruby中:
things.group_by {|thing| thing.type }
使用Symbol#to_proc
到
things.group_by(&:type)
不幸的是,ECMAScript没有groupBy
,也没有非现有属性的默认值,但 有Array.prototype.reduce
:
things.reduce(function (acc, thing) {
(acc[thing.type] || (acc[thing.type] = [thing])).push(thing);
return acc;
}, {});
答案 2 :(得分:0)
几乎相同的代码,但工作方式有点不同,您可以更轻松地使用花哨的集合函数并将逻辑分开:
var a = {set:function(type,thing){
if (this[type]) {
this[type].push(thing);
} else {
this[type] = [thing];
}
}};
a.set('a',0);
a.set('b',1);
a.set('a',2);