Class: Hash

Inherits:
Object show all
Includes:
Pairable
Defined in:
lib/sixarm_ruby_ramp/hash.rb

Overview

Hash extensions

Instance Method Summary collapse

Methods included from Pairable

#each_key!, #each_pair!, #each_sort, #each_value!, #map_key, #map_pair, #map_value, #yield_pair

Instance Method Details

#merge_recurse(other_hash) ⇒ Object

Return a new hash containing the contents of other_hash and the contents of hsh.

If no block is specified, the value for entries with duplicate keys will be that of other_hash; if the values are both hashes, then this method recurses.

Otherwise the value for each duplicate key is determined by calling the block with the key, its value in hsh and its value in other_hash.

@example:

h1 = {a: 'b', c: {d: 'e'}}
h2 = {a: 'B', c: {d: 'E'}}
h1.merge_recurse(h2)
#=> {a: 'B', c: {d: 'E'}}


48
49
50
51
52
53
54
55
56
# File 'lib/sixarm_ruby_ramp/hash.rb', line 48

def merge_recurse(other_hash)
  merge(other_hash){|key, oldval, newval|
    if oldval.is_a?(Hash) && newval.is_a?(Hash)
      oldval.merge_recurse(newval)
    else
      newval
    end
  }
end

#pivot(direction = 'keys', &block) ⇒ Object

Hash#pivot aggregates values for a hash of hashes, for example to calculate subtotals and groups.

Suppose you have data arranged by companies, roles, and headcounts.

  data = {
  "Apple"     => {"Accountants" => 11, "Designers" => 22, "Developers" => 33},
  "Goggle"    => {"Accountants" => 44, "Designers" => 55, "Developers" => 66},
  "Microsoft" => {"Accountants" => 77, "Designers" => 88, "Developers" => 99},
}

To calculate each company’s total headcount, you pivot up, then sum:

data.pivot(:up,&:sum)
=> {
 "Apple"=>66,
 "Goggle"=>165,
 "Microsoft"=>264
}

To calculate each role’s total headcount, you pivot down, then sum:

 data.pivot(:down,&:sum)
 => {
  "Accountants"=>132,
  "Designers"=>165,
  "Developers"=>198
 }

Generic example:
 h={
  "a"=>{"x"=>1,"y"=>2,"z"=>3},
  "b"=>{"x"=>4,"y"=>5,"z"=>6},
  "c"=>{"x"=>7,"y"=>8,"z"=>9},
 }
 h.pivot(:keys) => {"a"=>[1,2,3],"b"=>[4,5,6],"c"=>[7,8,9]}
 h.pivot(:vals) => {"x"=>[1,4,7],"y"=>[2,5,8],"z"=>[3,6,9]}

Calculating subtotals

The pivot method is especially useful for calculating subtotals.

Block customization

You can provide a block that will be called for the pivot items.

Examples:

r = h.pivot(:keys)
r['a'].sum => 6
r['b'].sum => 15
r['c'].sum => 24
r=h.pivot(:vals)
r['x'].sum => 12
r['y'].sum => 15
r['z'].sum => 18
h.pivot(:keys){|items| items.max } => {"a"=>3,"b"=>6,"c"=>9}
h.pivot(:keys){|items| items.join("/") } => {"a"=>"1/2/3","b"=>"4/5/6","c"=>"7/8/9"}
h.pivot(:keys){|items| items.inject{|sum,x| sum+=x } } => {"a"=>6,"b"=>15,"c"=>24}
h.pivot(:vals){|items| items.max } => {"a"=>7,"b"=>8,"c"=>9}
h.pivot(:vals){|items| items.join("-") } => {"a"=>"1-4-7","b"=>"2-5-8","c"=>"3-6-9"}
h.pivot(:vals){|items| items.inject{|sum,x| sum+=x } } => {"a"=>12,"b"=>15,"c"=>18}


126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/sixarm_ruby_ramp/hash.rb', line 126

def pivot(direction='keys',&block)
  a=self.class.new
  direction=direction.to_s
  up=pivot_direction_up?(direction)
  each_pair{|k1,v1|
    v1.each_pair{|k2,v2|
      k = up ? k1 : k2
      a[k]=[] if (a[k]==nil or a[k]=={})
      a[k]<<(v2)
    }
  }
  if block
    a.each_pair{|key,val| a[key]=block.call(val)}
  end
  a
end

#size?Boolean

Does the hash contain any items?

Returns:

  • (Boolean)

    true if size > 0



15
16
17
# File 'lib/sixarm_ruby_ramp/hash.rb', line 15

def size?
  size>0
end

#sort_by_keysHash

Sort the hsh items by the keys.

Examples:

h = {"c" => "cherry", "b" => "banana", "a" =>"apple" }
h.sort_keys => {"a" => "apple", "b" => "banana", "c" => "cherry"}

Returns:

  • (Hash)

    a new hash sorted by the keys



27
28
29
# File 'lib/sixarm_ruby_ramp/hash.rb', line 27

def sort_by_keys
  Hash[sort]
end