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 capitalize
d 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
Check If String Contains Any Substring in an Array in Ruby
Weird Rails Error "Permission Denied: Bin/Rails" for Old Rails Apps
Carrierwave - Resizing Images to Fixed Width
How to Setup Urls for Static Site with Ruby Rack on Heroku
Ruby - Activerecord::Connectionnotestablished
Do You Know an Alternative Ctags Generator for Ruby
Scientific Programming with Ruby
Dynamically Define Named Classes in Ruby
Run Delayed Jobs and Sidekiq at the Same Time
How to Convert Character Encoding with Ruby 1.9
Rails 4.1 Can't Deploy via Capistrano 3
"Don't Run Bundler as Root" - What Is the Exact Difference Made by Using Root
Using Ruby, Reading a File, Containing Name/Value Pairs into a Hash
Most of My Assets Suddenly Return 404 After a Push to Heroku