Pigeon Organizer Lab
(Source/Credits: https://dev.to/harlessmark/pigeon-organizer-lab-46n6)
Problem I'm given a hash of information and I need to rearrange them into a new hash sorte...
Problem
I'm given a hash of information and I need to rearrange them into a new hash sorted in a different way.
To go from this:
ruby
pigeon_data = {
:color => {
:purple => ["Theo", "Peter Jr.", "Lucky"],
:grey => ["Theo", "Peter Jr.", "Ms. K"],
:white => ["Queenie", "Andrew", "Ms. K", "Alex"],
:brown => ["Queenie", "Alex"]
},
:gender => {
:male => ["Alex", "Theo", "Peter Jr.", "Andrew", "Lucky"],
:female => ["Queenie", "Ms. K"]
},
:lives => {
"Subway" => ["Theo", "Queenie"],
"Central Park" => ["Alex", "Ms. K", "Lucky"],
"Library" => ["Peter Jr."],
"City Hall" => ["Andrew"]
}
}
To this:
ruby
pigeon_list = {
"Theo" => {
:color => ["purple", "grey"],
:gender => ["male"],
:lives => ["Subway"]
},
"Peter Jr." => {
:color => ["purple", "grey"],
:gender => ["male"],
:lives => ["Library"]
},
"Lucky" => {
:color => ["purple"],
:gender => ["male"],
:lives => ["Central Park"]
},
"Ms. K" => {
:color => ["grey", "white"],
:gender => ["female"],
:lives => ["Central Park"]
},
"Queenie" => {
:color => ["white", "brown"],
:gender => ["female"],
:lives => ["Subway"]
},
"Andrew" => {
:color => ["white"],
:gender => ["male"],
:lives => ["City Hall"]
},
"Alex" => {
:color => ["white", "brown"],
:gender => ["male"],
:lives => ["Central Park"]
}
}
What I Learned
While this one was challenging, I learned the most from this lab so far.
-
How to iterate through a hash using
.each
and assigning the keys and values different names. -
I found that creating a new hash required to check to see if it exists which I found interesting. What I though I could do in one line, I had to do in three. I later found out I could do it in a single line using
pigeon_list[:name] || = {}
but I'm not sure how to use it yet. -
I re-learned how to change something to a string using
.to_s
Final Iteration
ruby
def nyc_pigeon_organizer(data)
pigeon_list = {}
data.each do |color_gender_lives, value|
value.each do |stats, all_names|
all_names.each do |name|
if pigeon_list[name] == nil
pigeon_list[name] = {}
end
if pigeon_list[name][color_gender_lives] == nil
pigeon_list[name][color_gender_lives] = []
end
pigeon_list[name][color_gender_lives].push(stats.to_s)
end
end
end
pigeon_list
end
Comments section
baweaver
•May 1, 2024
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. Perhapsattribute_name
orproperty
?That would bring us to
value
andstats
andall_names
. They're not as much values as they are the actualattributes
orproperties
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
```
lagofelipe
•May 1, 2024
Thanks Brandon, that was a super useful explanation and insight,....just awesome stuff