Module: MoreCoreExtensions::StableSorting

Defined in:
lib/more_core_extensions/core_ext/array/sorting.rb

Instance Method Summary collapse

Instance Method Details

#tabular_sort(col_names = nil, order = nil, &block) ⇒ Object

Sorts an Array of Hashes by specific columns.

Rows are sorted by col_names, if given, otherwise by the given block.

The +order+ parameter can be given :ascending or :descending and
defaults to :ascending.

Note:

  • Strings are sorted case-insensitively

  • nil values are sorted last

  • Boolean values are sorted alphabetically (i.e. false then true)

    [

    {:col1 => 'b', :col2 => 2},
    {:col1 => 'b', :col2 => 1},
    {:col1 => 'A', :col2 => 1}
    

    ].tabular_sort([:col1, :col2])

    # => [ # => ‘A’, :col2 => 1, # => ‘b’, :col2 => 1, # => ‘b’, :col2 => 2 # ]



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/more_core_extensions/core_ext/array/sorting.rb', line 25

def tabular_sort(col_names = nil, order = nil, &block)
  # stabilizer is needed because of
  # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/170565
  stabilizer = 0
  nil_rows, sortable =
    partition do |r|
      Array(col_names).any? { |c| r[c].nil? }
    end

  data_array =
    if col_names
      sortable.sort_by do |r|
        stabilizer += 1
        [Array(col_names).map do |col|
          val = r[col]
          val = val.downcase if val.kind_of?(String)
          val = val.to_s     if val.kind_of?(FalseClass) || val.kind_of?(TrueClass)
          val
        end, stabilizer]
      end
    else
      sortable.sort_by(&block)
    end.to_a

  data_array += nil_rows

  data_array.reverse! if order == :descending
  data_array
end