Какой хороший шаблон JavaScript для классификации вещей по типам? - PullRequest
1 голос
/ 21 ноября 2010

Я ищу способ (в 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];
  }
}

Ответы [ 3 ]

1 голос
/ 21 ноября 2010

Я не уверен, что это хороший шаблон, но он похож на ваш пример с рубином:

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 голос
/ 21 ноября 2010

В 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 его элементов, который также встроен в 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;
}, {});
0 голосов
/ 21 ноября 2010

почти тот же код, но работает немного по-другому, вы можете использовать функцию необычного множества проще, и она разделяет логику:

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