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"}