I'm wondering if there is a more canonical way to do this in ruby 1.9
I have an array with a bunch of objects and I want to group them into a Hash using a property of each object in the array.
Very simplified example:
> sh = {}
=> {}
> aers = %w(a b c d ab bc de abc)
=> ["a", "b", "c", "d", "ab", "bc", "de", "abc"]
> aers.each do |aer|
> sh[aer.size] = [] if sh[aer.size].nil?
> sh[aer.size] << aer
> end
=> ["a", "b", "c", "d", "ab", "bc", "de", "abc"]
> sh
=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]}
I tried this, but its output is wrong (as you can see):
sh = Hash.new([])
=> {}
> aers.each do |aer|
> sh[aer.size] << aer
> end
=> ["a", "b", "c", "d", "ab", "bc", "de", "abc"]
> sh
=> {}
Use reduce() to Group an Array of Objects in JavaScript The most efficient way to group an array of objects in JavaScript is to use the reduce() function. This method executes each array element's (specified) reducer function and produces a single output value.
The most efficient method to group by a key on an array of objects in js is to use the reduce function. The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value.
Arrays also have built-in properties, such as array. length . The length property carries an integer value that denotes the length of an array. In general, built-in properties can be frequently found in predefined JavaScript objects like arrays.
Just as object properties can store values of any primitive data type (as well as an array or another object), so too can arrays consist of strings, numbers, booleans, objects, or even other arrays.
Ruby has anticipated your need, and has got you covered with Enumerable#group_by
:
irb(main):001:0> aers = %w(a b c d ab bc de abc)
#=> ["a", "b", "c", "d", "ab", "bc", "de", "abc"]
irb(main):002:0> aers.group_by{ |s| s.size }
#=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]}
In Ruby 1.9, you can make this even shorter with:
irb(main):003:0> aers.group_by(&:size)
#=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]}
Phrogz is correct, group_by is there for the taking. Your code contains one of ruby's gotcha's.
aers = %w(a b c d ab bc de abc)
sh = Hash.new([]) # returns the _same_ array everytime the key is not found.
# sh = Hash.new{|h,v| h[v] = []} # This one works
p sh, sh.default
aers.each do |aer|
sh[aer.size] << aer #modifies the default [] every time
end
p sh, sh.default
p sh[5]
Output
{}
[]
{}
["a", "b", "c", "d", "ab", "bc", "de", "abc"]
["a", "b", "c", "d", "ab", "bc", "de", "abc"]
You can also accomplish this by chaining methods... which might only be of academic interest for this problem, but is still a good technique to be familiar with.
irb(main):017:0> sh = {}
=> {}
irb(main):018:0> aers.collect{|k| k.size}.uniq!.each{|k| sh[k] = aers.select{|j| j.size == k}}
=> [1, 2, 3]
irb(main):019:0> sh
=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]}
irb(main):020:0>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With