Ruby: How to Group a Ruby Array

Ruby: How to group a Ruby array?

list.group_by(&:capitalize).map {|k,v| [k, v.length]}
#=> [["Master of puppets", 3], ["Enter sandman", 2], ["Nothing else matters", 1]]

The group by creates a hash from the capitalized version of an album name to an array containing all the strings in list that match it (e.g. "Enter sandman" => ["Enter Sandman", "Enter sandman"]). The map then replaces each array with its length, so you get e.g. ["Enter sandman", 2] for "Enter sandman".

If you need the result to be a hash, you can call to_h on the result or wrap a Hash[ ] around it.

Group by, array of arrays in ruby

Use following

some_array.group_by{|a| [a[0], a[1]]}
.map{|key, value| key + [value.map(&:last)]}
.flatten(1)

For multiple values in group by

2.3.1 :046 > some_array = [["FANUC CORP", "100048", 9], ["FANUC CORP", "100048", 26]
, ["FANUC CORP", "100048", 23], ["FANUC CORP", "100048", 111]
, ["FANUC CORP", "100049", 19],["FANUC CORP", "100049", 126],
["FANUC CORP", "100049", 123], ["FANUC CORP", "100049", 1111]]
=> [["FANUC CORP", "100048", 9], ["FANUC CORP", "100048", 26],
["FANUC CORP", "100048", 23], ["FANUC CORP", "100048", 111],
["FANUC CORP", "100049", 19], ["FANUC CORP", "100049", 126],
["FANUC CORP", "100049", 123], ["FANUC CORP", "100049", 1111]]

2.3.1 :047 > some_array.group_by{|a| [a[0], a[1]]}
.map{|key, value| key + [value.map(&:last)]}
.flatten(1)
=> ["FANUC CORP", "100048", [9, 26, 23, 111],
"FANUC CORP", "100049", [19, 126, 123, 1111]]

Ruby group_by in array of arrays

fruits.group_by {|(fruit, day)| fruit }.map {|fruit, match| [fruit, match.count] }

How to group array elements by index?

You can use slice_after to slice the array after each item whose index is in idx:

idx = [1, 5, 7]
arr = %w[a b c d e f g h i j k]

arr.enum_for(:slice_after).with_index { |_, i| idx.include?(i) }.to_a
#=> [["a", "b"], ["c", "d", "e", "f"], ["g", "h"], ["i", "j", "k"]]

That enum_for is (unfortunately) needed to chain slice_after and with_index.

Ruby Array of Arrays Group and Count by Values

Using Enumerable#group_by:

Array.group_by { |month, b| month }.map{ |month, xs|
[month,
xs.count {|_, b| !b}, # false
xs.count {|_, b| b}] # true
}
# => [["June", 3, 0], ["October", 1, 0]]

Ruby group array of arrays to merge them into one single array based on unique key in arrays

I'm not certain that I understand the question but I expect you may be looking for the following.

arr = [
["ABC", "5A2", nil, "88474"],
["ABC", nil, "2", "88474"],
["ABC", nil, nil, "88474"],
["ABC", nil, nil, "88474"],
["Jack", "5A2", nil, "05195"],
["Jack", nil, "2", "05195"],
["Jack", nil, nil, "05195"],
["Jack", nil, nil, "05195"]
]

arr.each_with_object({}) do |a, h|
h.update(a.first=>a) { |_k, oa, na| oa.zip(na).map { |ov, nv| ov.nil? ? nv : ov } }
end.values
#=> [["ABC", "5A2", "2", "88474"], ["Jack", "5A2", "2", "05195"]]

This uses the form of Hash#update (a.k.a. merge!) that employs the block

{ |_k, oa, na| oa.zip(na).map { |ov, nv| ov.nil? ? nv : ov } }

to determine the values of keys that are present in both the hash being built (h) and the hash being merged ({ a.first=>a }). See the doc for a description of the three block variables, _k, oa and na.1

I can best explain how the calculations procede by salting the code with puts statements and running it with an abbreviated array arr.

arr = [
["ABC", "5A2", nil, "88474"],
["ABC", nil, "2", "88474"],
["Jack", "5A2", nil, "05195"],
["Jack", nil, "2", "05195"],
]
arr.each_with_object({}) do |a, h|
puts "\na = #{a}"
puts "h = #{h}"
puts "a.first=>a = #{a.first}=>#{a}"
h.update(a.first=>a) do |_k, oa, na|
puts "_k = #{_k}"
puts "oa = #{oa}"
puts "na = #{na}"
a = oa.zip(na)
puts "oa.zip(na) = #{a}"
a.map do |ov, nv|
puts " ov = #{ov}, nv = #{nv}"
puts " ov.nil? ? nv : ov = #{ov.nil? ? nv : ov}"
ov.nil? ? nv : ov
end
end
end.tap { |h| puts "h = #{h}" }.values
#=> [["ABC", "5A2", "2", "88474"], ["Jack", "5A2", "2", "05195"]]

The following is displayed.

a = ["ABC", "5A2", nil, "88474"]
h = {}
a.first=>a = ABC=>["ABC", "5A2", nil, "88474"]
(The block is not called here because h does not have a key "ABC")

a = ["ABC", nil, "2", "88474"]
h = {"ABC"=>["ABC", "5A2", nil, "88474"]}
a.first=>a = ABC=>["ABC", nil, "2", "88474"]
_k = ABC
oa = ["ABC", "5A2", nil, "88474"]
na = ["ABC", nil, "2", "88474"]
oa.zip(na) = [["ABC", "ABC"], ["5A2", nil], [nil, "2"], ["88474", "88474"]]
ov = ABC, nv = ABC
ov.nil? ? nv : ov = ABC
ov = 5A2, nv =
ov.nil? ? nv : ov = 5A2
ov = , nv = 2
ov.nil? ? nv : ov = 2
ov = 88474, nv = 88474
ov.nil? ? nv : ov = 88474

a = ["Jack", "5A2", nil, "05195"]
h = {"ABC"=>["ABC", "5A2", "2", "88474"]}
a.first=>a = Jack=>["Jack", "5A2", nil, "05195"]
(The block is not called here because h does not have a key "Jack")

a = ["Jack", nil, "2", "05195"]
h = {"ABC"=>["ABC", "5A2", "2", "88474"], "Jack"=>["Jack", "5A2", nil, "05195"]}
a.first=>a = Jack=>["Jack", nil, "2", "05195"]
_k = Jack
oa = ["Jack", "5A2", nil, "05195"]
na = ["Jack", nil, "2", "05195"]
oa.zip(na) = [["Jack", "Jack"], ["5A2", nil], [nil, "2"], ["05195", "05195"]]
ov = Jack, nv = Jack
ov.nil? ? nv : ov = Jack
ov = 5A2, nv =
ov.nil? ? nv : ov = 5A2
ov = , nv = 2
ov.nil? ? nv : ov = 2
ov = 05195, nv = 05195
ov.nil? ? nv : ov = 05195
h = {"ABC"=>["ABC", "5A2", "2", "88474"], "Jack"=>["Jack", "5A2", "2", "05195"]}

1. As is common practice, I began the name of the common key, _k, with an underscore to signal to the reader that it is not used in the block calculation. Often you will see such a block variable represented by an underscore alone.

Group array of arrays and select some column in Ruby

A one-pass solution with inject:

array.inject({}) { | a, (v, k, _) | a[k] ||= []; a.update(k => a[k] << v) }

Or a bit cleaner:

array.inject(Hash.new { | h, k | h[k] = [] }) { | a, (v, k, _) | a.update(k => a[k] << v) }

This is the functional way of writing:

result = {}
array.each do | v, k, _ |
result[k] = [] unless result.has_key? k
result[k] << v
end

If you encounter performance issues, the update should be avoided:

array.inject({}) { | a, (v, k, _) | a[k] ||= []; a[k] << v; a }

For completeness, there is also each_with_object which is a bit more suitable here:

array.each_with_object({}) { | (v, k, _), a | a[k] ||= [];  a[k] << v }


Related Topics



Leave a reply



Submit