如果array 很大并且性能很重要,您可以编写以下内容。
array.group_by(&:class).sort_by { |k,_| k.to_s }.flat_map(&:last)
#=> [{:one=>"one"}, 1, "1", "one", :one, true]
# Hash Integer String String Symbol TrueClass
计算步骤如下。
h = array.group_by(&:class)
#=> {Integer=>[1], String=>["1", "one"], TrueClass=>[true],
# Hash=>[{:one=>"one"}], Symbol=>[:one]}
a = h.sort_by { |k,_| k.to_s }
#=> [[Hash, [{:one=>"one"}]], [Integer, [1]], [String, ["1", "one"]],
# [Symbol, [:one]], [TrueClass, [true]]]
a.flat_map(&:last)
#=> [{:one=>"one"}, 1, "1", "one", :one, true]
请参阅Enumerable#group_by、Enumerable#sort_by 和 Enumerable#flat_map。
设n为array中的元素个数,m为array中的元素所代表的唯一类的个数,计算各组件的计算复杂度如下。
group_by(&:class) : O(n)
sort_by { |k,_| k.to_s } : O(m*log(m))
flat_map(&:last) : O(m)
相比之下,传统排序的计算复杂度为O(n*log(n))。
对于问题中给出的array的例子,
n = array.size
#=> 6
m = array.map(&:class).uniq.size
#=> 5
显然,在这种情况下,传统的排序方法是最快的。但是,如果n 很大而m 相对较小,则相对计算速度将由O(m*log(m)) 和O(n*log(n)) 决定,这给我提出的方法带来了很大的优势。
请注意,这种方法适用于集合的元素e 将通过方法m 排序的任何情况,这样m(e) 的唯一值的数量与大小相比相对较小集合。