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