Использование group_by
- хороший подход, поскольку он сохраняет порядок элемента:
hash = arry.group_by(&:class)
#=> {
# Integer => [1, 2, 3, 4, 5, 34],
# TrueClass => [true],
# FalseClass => [false],
# NilClass => [nil, nil],
# String => ["Hello", "World"]
# }
. Мы можем использовать sort_by
для сортировки хеша по ключам на основе каждогоключи index
в массиве order
.Если класс отсутствует в orders
, мы используем массив size
в качестве запасного варианта, чтобы отсортировать его последним:
sorted = hash.sort_by { |k, _| order.index(k) || order.size }
#=> [
# [String, ["Hello", "World"]],
# [Integer, [1, 2, 3, 4, 5, 34]],
# [NilClass, [nil, nil]],
# [TrueClass, [true]],
# [FalseClass, [false]]
# ]
Наконец, flat_map
извлекает last
часть каждого элемента:
sorted.flat_map(&:last)
#=> ["Hello", "World", 1, 2, 3, 4, 5, 34, nil, nil, true, false]
Вы также можете использовать sort_by
без предварительной группировки, но это может перемешать элементы с тем же классом:
arry.sort_by { |e| order.index(e.class) || order.size }
#=> ["World", "Hello", 3, 4, 5, 1, 2, 34, nil, nil, true, false]
Это потому, что sort_by
не стабильно.
Чтобы исправить это, мы должны принять во внимание их индексы:
arry.sort_by.with_index { |e, i| [order.index(e.class) || order.size, i] }
#=> ["Hello", "World", 1, 2, 3, 4, 5, 34, nil, nil, true, false]
Если вы также хотите сопоставить подклассы (например, make Integer
match Fixnum
в более старых версиях Ruby), вы должны передать блок index
:
order.index { |cls| e.is_a?(cls) }