Reputation: 1076
I have an array of students objects (Student.all) and each object has a name
and a class_id
.
I want to find students with same class_id and concat their names into the same object, the others remain the same. I mean, turn this:
[
{
id: 1,
name: 'Joe',
class_id: 55
},
{
id: 2,
name: 'Bill',
class_id: 55
},
{
id: 3,
name: 'Moe',
class_id: 70
},
{
id: 4,
name: 'Larry',
class_id: 80
},
{
id: 5,
name: 'Phill',
class_id: 80
}
]
Into this:
[
{
id: 1,
name: 'Joe/Bill',
class_id: 55
},
{
id: 3,
name: 'Moe',
class_id: 70
},
{
id: 4,
name: 'Larry/Phill',
class_id: 80
}
]
Upvotes: 0
Views: 33
Reputation: 10738
Assuming you're only after creating the array (as opposed to updating the DB) you can do something like this:
arr.group_by{|x| x[:class_id]}
.values.map{|x| x.reduce{|m,v| m[:name] = "#{m[:name]}/#{v[:name]}";m}}
If you care about the original array you can make a small change:
arr.group_by{|x| x[:class_id]}
.values.map{|x| x[1..-1].reduce(x.first){|m,v| m[:name] = "#{m[:name]}/#{v[:name]}";m}}
The result:
[
{:id=>1, :name=>"Joe/Joe/Bill", :class_id=>55},
{:id=>3, :name=>"Moe", :class_id=>70},
{:id=>4, :name=>"Larry/Larry/Phill", :class_id=>80}
]
Upvotes: 3
Reputation: 6674
My solution is to use Enumerable#group_by
.
students = [...] # the source array
students.group_by(&:class_id)
# => {
55 => [
{
:id => 1,
:name => "Joe",
:class_id => 55
},
{
:id => 2,
:name => "Bill",
:class_id => 55
}
],
70 => [
{
:id => 3,
:name => "Moe",
:class_id => 70
}
],
80 => [
{
:id => 4,
:name => "Larry",
:class_id => 80
},
{
:id => 5,
:name => "Phil",
:class_id => 80
}
]
}
# Code in reduce block may need to be changed to fit your demand
students.group_by(&:class_id).reduce([]) do |ret, (k,v)|
st = v.first
st.name = v.map(&:name).join('/')
ret << st
end
# => target
Upvotes: 2