Ruby Array of Hash. Group_By and Modify in One Line

Ruby array of hash. group_by and modify in one line

array.group_by{|h| h[:type]}.each{|_, v| v.replace(v.map{|h| h[:name]})}
# => {"Meat"=>["one", "two"], "Fruit"=>["four"]}

Following steenslag's suggestion:

array.group_by{|h| h[:type]}.each{|_, v| v.map!{|h| h[:name]}}
# => {"Meat"=>["one", "two"], "Fruit"=>["four"]}

Ruby - array of hashes group by based on similar hash key

You need to group_by and then reduce values merging them.

input.
group_by { |h| h["PROJECT"] }.
values.
map do |v|
v.reduce({}) do |acc, h|
acc.merge(h) { |_, v1, v2| v1 == v2 ? v1 : [*v1, *v2] }
end
end

#⇒ [{"PROJECT"=>"awesome_project1",
# "VERSION"=>[128, 64],
# "STATUS"=>["not required", "scheduled"]},
# {"PROJECT"=>"awesome_project2",
# "VERSION"=>32,
# "STATUS"=>"finished"}]

Ruby hashes group by multiple value

This seems to do what you want:

transformed_hash = initial_hash
.group_by { |x| x['name'] }
.map { |k, v| [k, v.group_by{ |x| x['folder'] }] }
.to_h

Group array of hashes by multiple keys

I would do it this way:

def group_hashes arr, group_fields
arr.group_by {|hash| hash.values_at(*group_fields).join ":" }.values.map do |grouped|
grouped.inject do |merged, n|
merged.merge(n) do |key, v1, v2|
group_fields.include?(key) ? v1 : (v1.to_f + v2.to_f).to_s
end
end
end
end

You can group by multiple keys by joining them with some delimiter, see arr.group_by {|hash| hash.values_at(*group_fields).join ":" }

And I suppose, you don't need sum_field, because generally all fields that aren't grouped should be summed up.

Ruby group hashes based on matching keys and store the value of non matching keys in an array

You can try grouping by key and value and then map the revenue values:

foos
.group_by { |e| e.values_at(:key, :value) }
.map do |(key, value), values|
{ key: key, value: value, revenue: values.map { |e| e[:revenue] } }
end
# [{:key=>"Foo", :value=>1, :revenue=>[2, 4]}, {:key=>"Bar", :value=>2, :revenue=>[7]}, {:key=>"bar", :value=>2, :revenue=>[9]}, {:key=>"Zampa", :value=>4, :revenue=>[9]}]

i want to make a group Hash by keys and add values

I'd use the each_with_object method.
(key, value) here is a deconstruction of each key/value pair like 93=>1, hash is an intermediate object to store the result.

data.each_with_object({}) do |(key, value), hash|
result_key =
case key
when 10..19 then 1
when 20..29 then 2
when 90..99 then 9
end
next if result_key.nil?
hash[result_key] ||= 0
hash[result_key] += value
end

For the provided input I got {9=>2, 2=>7856, 1=>267}

UPD

A shorter solution suggested by Holger Just and Stefan in the comments below.

data.each_with_object(Hash.new(0)) do |(key, value), hash|
hash[key / 10] += value
end

With Hash.new(0) the initial object will be a hash with the default value 0

> hash = Hash.new(0)
=> {}
> hash[1]
=> 0

Ruby multiple group_by of array

Quick answer, using your code above:

y = [{:a=>"2017-01-01", :b=>"2", :c=>"1"}, {:a=>"2017-01-01", :b=>"2", :c=>"2"}, {:a=>"2017-01-02", :b=>"5", :c=>"1"}]
p = y.group_by { |g| g[:a]}
q = p.map {|date, list| [date, list.group_by {|g| g[:b]}]}.to_h

This gives the desired result of:

q == {
"2017-01-01" => {
"2"=> [
{:a=>"2017-01-01", :b=>"2", :c=>"1"},
{:a=>"2017-01-01", :b=>"2", :c=>"2"}
]
},
"2017-01-02" => {
"5"=> [
{:a=>"2017-01-02", :b=>"5", :c=>"1"}
]
}
}

This slightly odd pattern of mapping the hash to a list of arrays, then converting it back to a hash (using to_h) can be simplified slightly if you are working with a Rails v4.2+ project, by use of Hash#transform_values:

p.transform_values {|list| list.group_by {|g| g[:b]}}

However with that said, it is generally considered bad practice to be manipulating complex, nested hash objects like this. If your code gets too complicated, you may wish to consider redesigning how it works, in a more Object-Oriented manner.

Using group_by but return an array of hashes

The reason the grouped values are Rails objects (your models) is due to the fact that you also start with these objects. You can use the attributes method to retrieve the attributes of a model instance as a hash.

The following achieves the result you want:

City.all.group_by { |city| city.state.name }
.transform_values { |cities| cities.map(&:attributes) }

If you only want specific attributes, use slice instead:

City.all.group_by { |city| city.state.name }
.transform_values { |cities| cities.map { |city| city.slice(:id, :name) } }

Note that slice will return an ActiveSupport::HashWithIndifferentAccess instance. Which mostly can be used in the same manner as a normal hash, but returns the same value for both hash[:name] and hash['name']. If you rather use a normal hash append a to_hash call after the slice call.



Related Topics



Leave a reply



Submit