Today’s Ruby Tuesday is on Enumerable#group_by.
Enumerable#group_by
takes a block and returns a hash whose keys are the distinct values returned from the block, and the values are a list of items for which the block returned the key they are associated with.
This sounds a lot more complex than if you see it in code, so we will do a group_by
of the range of numbers from one to ten, and group them by the result of calling even?
on them.
(1..10).group_by(&:even?) # => {false=>[1, 3, 5, 7, 9], true=>[2, 4, 6, 8, 10]}
We can se we have a hash with the two keys false
and true
, and the value for the key of false
is a list of all the odd numbers, and the value for true
is the list of the even numbers.
As the keys are just the return value, we can pass an array of strings, and group them by their first letter.
["foo", "bar", "bazz"].group_by(&:chr) # => {"f"=>["foo"], "b"=>["bar", "bazz"]}
Or we can group them by their length,
["foo", "bar", "bazz"].group_by(&:length) # => {3=>["foo", "bar"], 4=>["bazz"]}
Or, if we want to find some anagrams, we can group the words by the result of sorting their characters.
["tar", "rat", "bar", "rob", "art", "orb"].group_by {|word| word.chars.sort} # => {["a", "r", "t"]=>["tar", "rat", "art"], # ["a", "b", "r"]=>["bar"], # ["b", "o", "r"]=>["rob", "orb"]}
This is also useful for when you are trying to get the start of some data to plot in a graph or a histogram, such as the length example above, or if we wanted to get a hash to be able to plot the number of words in the system dictionary against their length.
File.readlines("/usr/share/dict/words"). map(&:strip). group_by(&:length). reduce({}) {|accum, kv| word_length, words = kv; accum[word_length] = words.length; accum} # => {1=>52, # 2=>160, # 3=>1420, # 5=>10230, # 4=>5272, # 8=>29989, # 7=>23869, # 9=>32403, # 6=>17706, # 11=>26013, # 10=>30878, # 12=>20462, # 14=>9765, # 16=>3377, # 15=>5925, # 20=>198, # 19=>428, # 17=>1813, # 13=>14939, # 18=>842, # 21=>82, # 22=>41, # 23=>17, # 24=>5}
–Proctor
Pingback: F#: Incorrect results when Seq.groupBy groups on a sequence? « news-rss feed form stackoverflow
Pingback: F# Friday – Seq.groupBy | Brad Collins
Pingback: Scala Saturday – Stream.groupBy | Brad Collins