DEV Community

Discussion on: Pigeon Organizer Lab

Collapse
 
baweaver profile image
Brandon Weaver

You may enjoy Hash constructors and what you can do with them.

For primitive values you can use Hash.new(0) to create something that works like a counter.

For more complex types, you need the block format, Hash.new { |h, k| h[k] = {} }. This ensures a brand new object for each key that the hash doesn't know about as a default value, rather than reusing the same one repeatedly. This also works with hashes containing arrays. You could even go as far as to mix the two and get something like this:

pigeon_list = Hash.new { |h, k| h[k] = Hash.new { |h2, k2| h2[k2] = [] } }

...and the most fun trick? You could make an infinitely deep hash if you really wanted to:

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

This works because h.default_proc is referring to the function that is called when a default value is needed, or in other words, magic recursive hashes:

[20] pry(main)> infinite_hash = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
=> {}
[21] pry(main)> infinite_hash[1][2][3][4][5][6][7] = 8
=> 8
[22] pry(main)> infinite_hash
=> {1=>{2=>{3=>{4=>{5=>{6=>{7=>8}}}}}}}

Using those ideas you can avoid the nil checks. If you were to use ||= instead it would have looked like this:

pigeon_list[name] ||= {}
pigeon_list[name][color_gender_lives] ||= []

...which would take out four extra lines.

Now names. Names names names, names are very important. color_gender_lives relies on knowledge of the data structure. What if it changed? Color, gender, and lives are all properties, or perhaps attributes of a pigeon. Perhaps attribute_name or property?

That would bring us to value and stats and all_names. They're not as much values as they are the actual attributes or properties of a pigeon.

Combining all these ideas, we might get code that looks something close to this:

def nyc_pigeon_organizer(data)
  pigeon_list = {}

  data.each do |attribute_name, attributes|
    attributes.each do |attribute_value, pigeon_names|
      pigeon_names.each do |name|
        pigeon_list[name] ||= {}
        pigeon_list[name][attribute_name] ||= []
        pigeon_list[name][attribute_name].push(attribute_value.to_s)
      end
    end 
  end

  pigeon_list
end
Collapse
 
lagofelipe profile image
Felipe Dolago

Thanks Brandon, that was a super useful explanation and insight,....just awesome stuff