Ruby - Sort array by class type

Viewed 96

Say I have an array of multiple class types

array = [ 1, "1", "one", true, { one: "one" }, :one ]

I want to sort this array by the class type in alphabetical order. For example :one.class => Sybmol would be ordered after 1.class => Fixnum

How can I achieve this?

2 Answers

You can use Enumerable#sort_by which accepts a block where you can invoke class and to_s on the receiver:

array.sort_by { |e| e.class.to_s }
# [{:one=>"one"}, 1, "1", "one", :one, true]

If array were large and performance were important you might write the following.

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 

The steps in the calculation are as follows.

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] 

See Enumerable#group_by, Enumerable#sort_by and Enumerable#flat_map.

Letting n be the number of elements in array and m being the number of unique classes represented by the elements of array, the computation complexities of each component of the calculation are as follows.

group_by(&:class)         : O(n)
sort_by { |k,_| k.to_s }  : O(m*log(m))
flat_map(&:last)          : O(m)

By contrast, a conventional sort has a computational complexity of O(n*log(n)).

For the example of array given in the question,

n = array.size
  #=> 6
m = array.map(&:class).uniq.size
  #=> 5

Clearly, the conventional method of sorting would be fastest in this case. If, however, n were large and m relatively small, relative computational speed would be determined by O(m*log(m)) versus O(n*log(n)), giving a large advantage to the method I proposed.

Note that this approach could be taken in any situation where elements e of a collection are to be sorted by a method m such that the number of unique values of m(e) is relatively small when compared to the size of the collection.

Related