我正在寻找一种方法,可以根据另一个数组中元素的类别对数组中的元素进行排序。我有:
order = [String, Integer, NilClass ,TrueClass]
arry = [1, 2, 3, 4, 5, true, false, nil, 34, nil, 'Hello', 'World']
在order
中,元素的顺序是动态的。结果应该是:
result_arry = ['Hello', 'World', 1, 2, 3, 4, 5, 34, nil, nil, true, false]
如何根据arry
中元素的类别对order
进行排序?
我尝试过:
hash = arry.group_by {|n| n.class }
# => {Fixnum=>[1, 2, 3, 4, 5, 34], TrueClass=>[true], FalseClass=>[false], NilClass=>[nil, nil], String=>["Hello", "World"]}
答案 0 :(得分:4)
使用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
根据order
数组中每个键的index
对哈希进行排序。如果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]]
# ]
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]
如果您还想匹配子类(例如,使旧版本的Ruby版本中的Integer
与Fixnum
匹配,则必须将一个块传递给index
:
order.index { |cls| e.is_a?(cls) }
答案 1 :(得分:3)
我认为这可行:
T Data
arry.sort_by{ |v|
order.map{ |c|
v.is_a?(Object.const_get(c)) ? -1 : 1
}
}
# ["Hello", "World", 1, 2, 3, 4, 5, 34, nil, nil, true, false]
将字符串转换为类。
答案 2 :(得分:1)
排序,本身是不必要的。
missing_classes = arry.map(&:class) - order
#=> [Symbol, FalseClass]
arry.group_by(&:class).values_at(*(order + missing_classes)).flatten
#=> ["Hello", "World", 1, 2, 3, 4, 5, 34, nil, nil, true, :cat, false]