将事物分类为类型的良好 JavaScript 模式是什么?

发布于 2024-10-03 05:16:04 字数 908 浏览 2 评论 0原文

我正在寻找一种方法(在 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];
  }
}

I'm looking for a way (in JavaScript) to collect a set of objects into multiple arrays, where each array contains a certain type of object, and the arrays are stored as values in an associative array, with the keys being the types. For example:

Input:

[<apple>, <cat>, <pear>, <mercedes>, <dog>, <ford>, <orange>]

Output:

{
  'fruit': [<apple>, <pear>, <orange>],
  'animal': [<cat>, <dog>],
  'car': [<mercedes>, <ford>]
}

In ruby, you could do the following:

things_by_type = {}
things.each do |thing|
  (things_by_type[thing.type] ||= []) << thing
end

which is nice and concise.

What's a good pattern for doing the same thing in JavaScript that's concise and efficient? I could do something like this, but it's not as nice:

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];
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

远昼 2024-10-10 05:16:04

我不确定这是否是一个好的模式,但它与您的 ruby​​ 示例类似:

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);
})

I'm not sure if it's a good pattern, but it's similar to your ruby sample:

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);
}

And if you can assume Javascript 1.6:

var things_by_type = {};
things.forEach(function(thing) {
  (things_by_type[thing.type] || (things_by_type[thing.type] = [])).push(thing);
})
海未深 2024-10-10 05:16:04

在 ruby​​ 中,您可以执行以下操作:

things_by_type = {}
things.each 做 |thing|
  (things_by_type[thing.type] ||= []) <<事物
结尾

简洁明了。

事实上,你可以让它变得更好。

首先,Hash.new 采用一个块参数,每次引用不存在的键时都会调用该参数。您可以使用它来创建该密钥。这样你就可以摆脱块内的条件逻辑。

things_by_type = Hash.new {|h, k| h[k] = [] }
things.each do |thing|
  things_by_type[thing.type] << thing
end

其次,这里的内容称为“折叠”或“减少”:将集合(对象数组)“折叠”或“减少”为单个值(哈希,令人困惑的是,它也恰好是一个集合,但仍然是一个值)。

通常,您可以通过查找初始化某些变量的位置,然后循环遍历集合并在循环的每次迭代中操作该变量,轻松地发现这种模式。

Ruby 通过 Enumerable#reduce 方法内置了折叠功能:

things.reduce(Hash.new {|h, k| h[k] = [] }) do |h, thing|
  h.tap { h[thing.type] << thing }
end

但是您真正所做的是按其元素的类型属性对数组进行分组,这也是构建的Ruby 中为 Enumerable#group_by

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;
}, {});

In ruby, you could do the following:

things_by_type = {}
things.each do |thing|
  (things_by_type[thing.type] ||= []) << thing
end

which is nice and concise.

Actually, you can make that even nicer.

First off, Hash.new takes a block argument which will be called every time a non-existing key is referenced. You can use that to create that key. That way you get rid of the conditional logic inside the block.

things_by_type = Hash.new {|h, k| h[k] = [] }
things.each do |thing|
  things_by_type[thing.type] << thing
end

Secondly, what you have here is called a fold or reduce: you are "folding" or "reducing" a collection (the array of objects) into a single value (the hash, which confusingly also happens to be a collection, but is nonetheless a single value).

You can generally easily spot this pattern by looking for places where you initialize some variable, then loop over a collection and manipulate that variable at every iteration of the loop.

Ruby has folding built in, via the Enumerable#reduce method:

things.reduce(Hash.new {|h, k| h[k] = [] }) do |h, thing|
  h.tap { h[thing.type] << thing }
end

But what you are really doing, is grouping the array by the type attribute of its elements, which is also built into Ruby as Enumerable#group_by:

things.group_by {|thing| thing.type }

Which can be further simplified by using Symbol#to_proc to

things.group_by(&:type)

Unfortunately, ECMAScript doesn't have groupBy, nor default values for non-existing properties, but it does have Array.prototype.reduce:

things.reduce(function (acc, thing) {
    (acc[thing.type] || (acc[thing.type] = [thing])).push(thing);
    return acc;
}, {});
不打扰别人 2024-10-10 05:16:04

几乎相同的代码,但工作方式有点不同,您可以更轻松地使用花哨的 set 函数,它分离了逻辑:

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);

almost the same code, but works a bit different, you can use the fancy set function easier and it separates logic:

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文