Array and Enumerable

Human Readable Sort

Human readable sort by Jeff Atwood

This code utilize <=>’s ability to sort / give total order to array:

  ["aa123.txt", "ka023.rb", "ka098.rb", "ka98", "a2.txt"].sort_by do |item| 
    item.to_s.split(/(\d+)/).map do |e| 
      [e.to_i, e]
    end 
  end #=> ["a2.txt", "aa123.txt", "ka023.rb", "ka098.rb", "ka98"]

We first split each item (file name) by its alpha, numeric, and extension components.

  "aa123.txt".to_s.split(/(\d+)/) # =>  ["aa", "123", ".txt"]

We then nullify any alphabetical characters to zero and convert numeric strings into their integer equivalent.

  ["aa", "123", ".txt"].map{ |e| [e.to_i, e] } # => [[0, ‘aa’], [123, "123"], [0, ‘text’]]
  
  # putting it all together
  "ka023.rb".to_s.split(/(\d+)/).map{ |e| [e.to_i, e] } # => [[0, "ka"], [23, "023"], [0, ".rb"]]

Lastly, we utilize <=>’s ability to give global orderings to arrays.

  [[0, "ka"], [23, "023"], [0, ".rb"]] <=> [[0, ‘aa’], [123, "123"], [0, ‘text’]] # => 1 (1st one bigger)
  [[0, ‘aa’], [123, "123"], [0, ‘text’]] <=> [[0, "ka"], [23, "023"], [0, ".rb"]] # => -1 (1st one smaller)

Override Array#uniq by modifying Object.eql?

Google Group Reference by Matz

Array#uniq creates hash internally to remove redundant values, so that comparison is done by eql? but it is filtered by hash value first. In other words, when you redefine “eql?” you have to redefine “hash” as well.

  class A
    attr_accessor :f
    def initialize f
       @f = f
    end
  
    def eql?( a2 )
      self.f == a2.f
    end
  
    def hash
      self.f.intern.hash  # hash must always return an integer
    end
  end

  [A.new(‘hehe’), A.new(‘hehe’)].uniq   # => [#<A:0×225bd70 @f="hehe">]

Hash

Convert to Array and Back

  h = Hash[ ‘a’ => 1, ‘b’ => 2, ‘c’ => 3 ]      # => {"a"=>1, "b"=>2, "c"=>3}
  a = h.to_a                                    # => [["a", 1], ["b", 2], ["c", 3]]
  Hash[  a.flatten ]                           # => {"a"=>1, "b"=>2, "c"=>3}
  Hash[  a.collect{ |e| e.reverse }.flatten ]  # => {1=>"a", 2=>"b", 3=>"c"}