Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

« Newer Snippets
Older Snippets »
Showing 1-10 of 41 total  RSS 

Convert two Arrays into one Hash (Ruby)

This is a way to merge two arrays into one hash.
The returned hash will have the same quantity of elements that the first(self) array.

class Array
def merge_into_hash(anArray)
tmp,hash = anArray.dup,{}
self.each {|key| hash[key] = tmp.shift}
hash
end
end

Hash#collate



# From: http://www.ruby-forum.com/topic/135807
# Author: Nobuyoshi Nakada

class Hash
   def collate(h)
      raise ArgumentError unless h.is_a?(Hash)
      update(h) { |key, *values| values }
      #update(h) { |key, *values| values.flatten.uniq }
   end
end

h1 = {:a=>1, :b=>2 }
h2 = {:a=>3, :b=>4, :c=>5}
h1.collate(h2)
p h1, h2     
#=> {:b=>[2, 4], :a=>[1, 3], :c=>5}
#=> {:b=>4, :a=>3, :c=>5}

puts
h1 = {:a=>1, :b=>2 }
h2 = {:a=>3, :b=>4, :c=>5}
h2.collate(h1)
p h1, h2     
#=> {:b=>2, :a=>1}
#=> {:b=>[4, 2], :a=>[3, 1], :c=>5}



Ruby Hash Power-Set

// adds a #power_set method to Hash class

# The Array power set is stolen from http://snippets.dzone.com/posts/show/3524
class Array
  # Returns the "power set" for this Array. This means that an array with all
  # subsets of the array's elements will be returned.
  def power_set
    # the power set line is stolen from http://johncarrino.net/blog/2006/08/11/powerset-in-ruby/
    inject([[]]){|c,y|r=[];c.each{|i|r<<i;r<<i+[y]};r}
  end
end

class Hash
  def power_set
    # Returns the "power set" for this Hash. This means that a array with hashes of all
    # subsets of the hash's (key => value) pairs will be returned.
    # Example:
    # >> {:feedback_type=>"", :language_code=>"", :comment=>""}.power_set
    #
    # [{}, {:comment=>""}, {:language_code=>""}, {:language_code=>"", :comment=>""}, {:feedback_type=>""}, {:feedback_type=>"", :comment=>""}, {:feedback_type=>"", :language_code=>""}, {:feedback_type=>"", :language_code=>"", :comment=>""}]
    
    hash_to_array = self.to_a
    array_power_set = hash_to_array.power_set
    hash_power_set = array_power_set.collect { |pairs| pairs.inject({}) { |hash,pair| hash[pair[0]] = pair[1]; hash } }
    hash_power_set
  end
end

Hash#deep_delete


class Object
   def deep_clone
      Marshal.load(Marshal.dump(self))
   end
end


class Hash

   # From: http://www.sameshirteveryday.com/2007/09/23/ruby-get-full-history-all-parents-of-a-hash-node
   # Author: Alex Gorbatchev
   # for further recursive hash methods see: 
   # - http://snippets.dzone.com/posts/show/1908
   # - http://snippets.dzone.com/posts/show/4706
   
   def nested_key(desired_key, &block)

      return false unless Hash === self
      #return false unless self.is_a?(Hash)

      self.each_pair do |k,v|  
         if k == desired_key or v.nested_key(desired_key, &block)  
            yield(k,v)  
            return true  
         end  
      end  

      return false  
   end


   def deep_values(key)   # cf. http://snippets.dzone.com/posts/show/1908 

      hash = self.deep_clone
      ret = []

      begin

         ar = []
         result = hash.nested_key(key) { |k, v| ar << k }
         break unless result
         ar = ar.reverse

         hk = ""
         ar.size.times { |i| hk << "[ar[#{i}]]" }
         #str = "hash" << hk << " rescue nil"
         str = "hash" << hk 

         # get value for hash key hk
         ret << eval(str)

         # delete the hash key
         key_to_delete = [ar.pop]

         hk = ""
         ar.size.times { |i| hk << "[ar[#{i}]]" }
         str = "hash" << hk
         str = str << ".delete(key_to_delete.first)"
         eval(str)


      end while result

      hash.clear  # optional
      ret

   end


   def deep_delete(key)

      hash = self

      begin

         ar = []
         result = hash.nested_key(key) { |k, v| ar << k }
         break unless result
         ar = ar.reverse

         # delete the hash key
         key_to_delete = [ar.pop]

         hk = ""
         ar.size.times { |i| hk << "[ar[#{i}]]" }
         str = "hash" << hk
         str = str << ".delete(key_to_delete.first)"
         eval(str)

      end while result

   end

end



puts
hash = {  
  :level_1 => {  
    :level_2 => {  :search => 'test1',
      :level_3 => {  
        :search => 'test2', :level_4 => {:search => 'test3'}
      }  
    }  
  }  
}  


require 'pp'

p hash
puts

pp hash
puts

hash.nested_key(:search) { |k, v| puts "#{k}  ::  #{v.inspect}" }

# prints out...
# search  ::  "test1"
# level_2  ::  {:search=>"test1", :level_3=>{:search=>"test2", :level_4=>{:search=>"test3"}}}
# level_1  ::  {:level_2=>{:search=>"test1", :level_3=>{:search=>"test2", :level_4=>{:search=>"test3"}}}}

puts


puts "DEEP VALUES"
p hash.deep_values(:search)   #=> ["test1", "test2", "test3"]
puts

puts "DEEP VALUES DELETED"
hash.deep_delete(:search)
p hash   #=> {:level_1=>{:level_2=>{:level_3=>{:level_4=>{}}}}}
puts

puts "DEEP VALUES"
p hash.deep_values(:search)   #=> []

Hash#deep_merge


# Hash#deep_merge
# From: http://pastie.textmate.org/pastes/30372, Elliott Hird
# Source: http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html
# This file contains extensions to Ruby and other useful snippits of code.
# Time to extend Hash with some recursive merging magic.


class Hash

  # Merges self with another hash, recursively.
  # 
  # This code was lovingly stolen from some random gem:
  # http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html
  # 
  # Thanks to whoever made it.

  def deep_merge(hash)
    target = dup
    
    hash.keys.each do |key|
      if hash[key].is_a? Hash and self[key].is_a? Hash
        target[key] = target[key].deep_merge(hash[key])
        next
      end
      
      target[key] = hash[key]
    end
    
    target
  end


  # From: http://www.gemtacular.com/gemdocs/cerberus-0.2.2/doc/classes/Hash.html
  # File lib/cerberus/utils.rb, line 42

  def deep_merge!(second)
    second.each_pair do |k,v|
      if self[k].is_a?(Hash) and second[k].is_a?(Hash)
        self[k].deep_merge!(second[k])
      else
        self[k] = second[k]
      end
    end
  end


#-----------------
        
   # cf. http://subtech.g.hatena.ne.jp/cho45/20061122
   def deep_merge2(other)
      deep_proc = Proc.new { |k, s, o|
         if s.kind_of?(Hash) && o.kind_of?(Hash)
            next s.merge(o, &deep_proc)
         end
         next o
      }
      merge(other, &deep_proc)
   end


   def deep_merge3(second)

      # From: http://www.ruby-forum.com/topic/142809
      # Author: Stefan Rusterholz

      merger = proc { |key,v1,v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
      self.merge(second, &merger)

   end


   def keep_merge(hash)
      target = dup
      hash.keys.each do |key|
         if hash[key].is_a? Hash and self[key].is_a? Hash
            target[key] = target[key].keep_merge(hash[key])
            next
         end
         #target[key] = hash[key]
         target.update(hash) { |key, *values| values.flatten.uniq }
      end
      target
   end

end


h = {:a => {:b => :c}}.merge({:a => {:l => :x}})
p h  #=> {:a=>{:l=>:x}}

h = {:a => {:b => :c}}.deep_merge({:a => {:l => :x}})
p h  #=> {:a=>{:b=>:c, :l=>:x}}
puts


h1 = {:a => {:b => :c}}
h2 = {:a => {:l => :x}}

h = h1.deep_merge(h2)
p h1, h2, h
puts

h = h1.deep_merge2(h2)
p h1, h2, h
puts

h = h1.deep_merge!(h2)
p h1, h2, h


h1 = {:a => {:b => :c}}
h2 = {:a => {:l => :x}}

p h1.deep_merge3(h2)
p h1, h2


first = {
  :data=>{
    :name=>{
      :first=>'Sam',
      :middle=>'I',
      :last=>'am'
    }
  }
}

second={
  :data=>{
    :name=>{
      :middle=>'you',
      :last=>'are'
    }
  }
}


p first.deep_merge3(second)
#=> {:data=>{:name=>{:middle=>"you", :first=>"Sam", :last=>"are"}}}

p first.keep_merge(second)
#=>  {:data=>{:name=>{:first=>"Sam", :middle=>["I", "you"], :last=>["am", "are"]}}}

Usefull Additions to the Hash Class

Rename keys and return a duplicate hash, or perform the method and modify the current hash.
Check each value in the hash and return true if they are all empty, otherwise return false.

class Hash
  def rename_key(old_key, new_key)
    return Hash.rename_key(self.dup, old_key, new_key)
  end
  
  def rename_key!(old_key, new_key)
    return Hash.rename_key(self, old_key, new_key)
  end
  
  def all_values_empty?
    self.each_value do |v|
      return false if v and v != ""
    end
    
    return true
  end
  
  private
    def self.rename_key(hsh, old_key, new_key)
      hsh[new_key.to_s] = hsh.delete(old_key.to_s)
      return hsh
    end
end

to_hoa

class Array
  
  # Make a hash of arrays out of an array
  # of somethings by involving each element.
  #
  # Pass a block returning each keys' name.
  #
  # Example usage:
  #
  # >> [1, 2, 3].to_hoa { |n| (n+96).chr }
  # => {"a"=>[1], "b"=>[2], "c"=>[3]}
  #
  # >> ['a', 'a', 'a', 'b', 'b', 'c'].to_hoa {|x|x}
  # => {"a"=>["a", "a", "a"], "b"=>["b", "b"], "c"=>["c"]}
    
  def to_hoa
    inject({}) { |h,v| (h[yield(v)] ||= []).push v; h }
  end

end


update: RoR provides group_by, which does exactly the same using Enumerable (thanks Matt for pointing this out).

Create nested hashes in Ruby


# From: http://www.ruby-forum.com/topic/111524
# Author: Daniel Martin

a = Hash.new{|h,k| h[k]=Hash.new(&h.default_proc) }

a[2][1]=2
a[2][2][3]=4
a[3][1][1][1]=1

p  a     #=> {2=>{1=>2, 2=>{3=>4}}, 3=>{1=>{1=>{1=>1}}}}


# From: http://www.ruby-forum.com/topic/130324
# Author: Bob Hutchison

class Hash
   def Hash.new_nested_hash
     Hash.new{|h,k| h[k]=Hash.new(&h.default_proc) }
   end
end

a = Hash.new_nested_hash

a[2][1]=2
a[2][2][3]=4
a[3][1][1][1]=1

p  a     #=> {2=>{1=>2, 2=>{3=>4}}, 3=>{1=>{1=>{1=>1}}}}


# From: http://www.rubyquiz.com/quiz113.html
# Author: Carl Porth

ar = ('a'..'g').to_a
p  ar.reverse.inject { |mem, var| {var => mem} }    #=> {"a"=>{"b"=>{"c"=>{"d"=>{"e"=>{"f"=>"g"}}}}}}

Random key from Ruby Hash (even faster)

I came across baby's code and then aiosup's from 2 years ago, and realized that I like the simplicity of one and the approach of the other. Kudos to both authors, and I found a way to combine the two approaches into one neat mechanism. More of my ruby here,

class Hash
  @keys_not_used = nil

  def random_key
          @keys_not_used = self.dup if (!@keys_not_used or @keys_not_used.size == 0)
	  key = @keys_not_used.keys[rand(@keys_not_used.size)]
	  @keys_not_used.delete(key)
          key
  end

end

Turn CSV with headers into Array of Hashes (in 5 lines or less)

This assumes you have a CSV file whose first line are headings/labels for the individual columns.

require 'csv'

csv_data = CSV.read 'data.csv'
headers = csv_data.shift.map {|i| i.to_s }
string_data = csv_data.map {|row| row.map {|cell| cell.to_s } }
array_of_hashes = string_data.map {|row| Hash[*headers.zip(row).flatten] }
« Newer Snippets
Older Snippets »
Showing 1-10 of 41 total  RSS