Этот подход включает в себя больше шагов, чем те, которые используют sort
или sort_by
, но для больших массивов это может быть быстрее, так как нет сортировки - что относительно дорого - участвует.
Код
def reorder_by_size(instances, size_order)
instances.each_with_object({}) { |inst, h| h.update(inst.name=>inst) }.
values_at(*(size_order & (instances.map { |s| s.name })))
end
Пример
Во-первых, давайте создадим массив экземпляров
class Sizes
attr_reader :name
def initialize(id, name)
@id = id
@name = name
end
end
так:
instances = [Sizes.new(5,'M'), Sizes.new(6,'M/L'), Sizes.new(7, 'XS/S')]
#=> [#<Sizes:0x007fa66a955ac0 @id=5, @name="M">,
# #<Sizes:0x007fa66a955a70 @id=6, @name="M/L">,
# #<Sizes:0x007fa66a955a20 @id=7, @name="XS/S">]
Затем
reorder_by_size(instances, @sizes_sort_order)
#=> [#<Sizes:0x007fa66a01dfc0 @id=7, @name="XS/S">,
# #<Sizes:0x007fa66a86fdb8 @id=5, @name="M">,
# #<Sizes:0x007fa66a8404f0 @id=6, @name="M/L">]
Объяснение
Для instances
, как определено для примера, сначала создать массив размеров в требуемом порядке:
names = @sizes_sort_order & (instances.map { |s| s.name })
#=> ["XS/S", "M", "M/L"]
Важно: док для Array#& говорится: «Порядок сохраняется из исходного массива».
Теперь мы можем создать желаемое переупорядочение без сортировки, создав хэш с ключами размеров и значений экземпляров, а затем воспользуемся Hash#values_at, чтобы извлечь экземпляры в нужном порядке.
instances.each_with_object({}) { |inst, h|
h.update(inst.name=>inst) }.values_at(*names)
#=> [#<Sizes:0x007fa66a01dfc0 @id=7, @name="XS/S">,
# #<Sizes:0x007fa66a86fdb8 @id=5, @name="M">,
# #<Sizes:0x007fa66a8404f0 @id=6, @name="M/L">]
Последняя операция включает в себя следующие два этапа.
h = instances.each_with_object({}) { |inst, h| h.update(inst.name=>inst) }
#=> {"M" => #<Sizes:0x007fa66a955ac0 @id=5, @name="M">,
# "M/L" => #<Sizes:0x007fa66a955a70 @id=6, @name="M/L">,
# "XS/S" => #<Sizes:0x007fa66a955a20 @id=7, @name="XS/S">}
h.values_at(*names)
#=> h.values_at(*["XS/S", "M", "M/L"])
#=> h.values_at("XS/S", "M", "M/L")
#=> [#<Sizes:0x007fa66a955a20 @id=7, @name="XS/S">,
# #<Sizes:0x007fa66a955ac0 @id=5, @name="M">,
# #<Sizes:0x007fa66a955a70 @id=6, @name="M/L">]
Посмотрите на [ 'перечислимых # sort_by'] (http://ruby-doc.org/core-2.2.0/Enumerable.html#method-i-sort_by) –