Flowdock

Notes posted by EdvardM

RSS feed
April 23, 2014
0 thanks

Does not symbolize hashes in nested arrays

If you have a nested structure containing arrays of hashes, you still need to do that on your own, eg.

module SymbolizeHelper
  def symbolize_recursive(hash)
    {}.tap do |h|
      hash.each { |key, value| h[key.to_sym] = map_value(value) }
    end
  end

  def map_value(thing)
    case thing
    when Hash
      symbolize_recursive(thing)
    when Array
      thing.map { |v| map_value(v) }
    else
      thing
    end
  end
end

Or, if you want to get really fancy with Ruby refinements (YMMV), one could do

module SymbolizeHelper
  extend self

  def symbolize_recursive(hash)
    {}.tap do |h|
      hash.each { |key, value| h[key.to_sym] = transform(value) }
    end
  end

  private

  def transform(thing)
    case thing
    when Hash; symbolize_recursive(thing)
    when Array; thing.map { |v| transform(v) }
    else; thing
    end
  end

  refine Hash do
    def deep_symbolize_keys
      SymbolizeHelper.symbolize_recursive(self)
    end
  end
end

And later say

using SymbolizeHelper # augmented Hash#deep_symbolize_keys is now available
July 23, 2012
2 thanks

Long-wanted functional extension

This is pretty nice method allowing you to build stuff in a functional way.

Lets say you want to build a hash from an array, keyed by array object, where each value is the number of same objects in the array.

# imperative style :-P

h = Hash.new(0)
[1, 3, 2, 3, 1, 3].each { |i| h[i] += 1 }
h # => {1=>2, 3=>3, 2=>1} 

# functional style, using inject. Note that you need to explicitly return the accumulator in the end

[1, 3, 2, 3, 1, 3].inject(Hash.new(0)) { |a, i| a[i] += 1; a } 
# => {1=>2, 3=>3, 2=>1} 

# using each_with_object. Note the reversed block params - accumulator is the last parameter. 
# Mnemonic: consistent with each_with_index, where object is the first parameter

[1, 3, 2, 3, 1, 3].each_with_object(Hash.new(0)) {|i, a| a[i] += 1}
# => {1=>2, 3=>3, 2=>1}