
[code]

    [
      {
        :id => 1,
        :data => 1
      },
      {
        :id => 1,
        :data => 2
      },
      {
        :id => 2,
        :data => 1
      },
      {
        :id => 2,
        :data => 2
      }
    ]
    
[/code]

↓こうしたい

[code]

    [
      {
        :id => 1,
        :data => [1,2]
      },
      {
        :id => 2,
        :data => [1,2]
      },
    ]
    
[/code]

ループがたくさんになってしまう上に、うまくいきません。


CC BY-SA 3.0
2015-09-18T10:04:51.717
16749
2018-11-12T14:15:51.760
10439
question
ruby
rubyでオブジェクトを綺麗にまとめたい


こんな感じでどうでしょうか？

[code]

    objects = [
      {
        :id => 1,
        :data => 1
      },
      {
        :id => 1,
        :data => 2
      },
      {
        :id => 2,
        :data => 1
      },
      {
        :id => 2,
        :data => 2
      }
    ]
    objects
      .map {|h| [h[:id], h[:data]] }
      .group_by(&:first)
      .map {|id, arr| { id: id, data: arr.map(&:last) } }
    # => [{:id=>1, :data=>[1, 2]}, {:id=>2, :data=>[1, 2]}]
    
[/code]

多少読みづらくても構わないなら、こんな書き方もできます。  
ループの回数は少なくなりそうです。

[code]

    data_holder = Hash.new {|h, k| h[k] = { id: k, data: [] } }
    objects.each_with_object(data_holder) { |object, holder|
      holder[object[:id]][:data] << object[:data]
    }.values
    
[/code]

`each_with_object` の代わりに `tap` を使うパターンもあります。

[code]

    Hash.new {|h, k| h[k] = { id: k, data: [] } }.tap {|hash|
      objects.each do |obj|
        id, data = obj.values_at(:id, :data)
        hash[id][:data] << data
      end
    }.values
    
[/code]

お好きな方法で実装してみてください。


CC BY-SA 3.0
2015-09-18T12:49:29.783
16754
2015-09-18T21:41:06.087
2015-09-18T21:41:06.087
85
85
16749
answer

[code]

    objects = [
      {
        :id => 1,
        :data => 1
      },
      {
        :id => 1,
        :data => 2
      },
      {
        :id => 2,
        :data => 1
      },
      {
        :id => 2,
        :data => 2
      }
    ]
    objects    
      .group_by{|h| h[:id]}
      .map {|k, h| {id: k, data: h.map {|h| h[:data]} }}
    
[/code]

Junichi Itoさんのコードを参考に  
group_byの前にarrayにしない方法も追記致します。


CC BY-SA 3.0
2015-10-19T01:36:42.077
17793
2015-10-19T01:36:42.077
12765
16749
answer

[code]

    hash = {}
    array.each do |obj|
      if hash[obj[:id]]
        hash[obj[:id]] << obj[:data]
      else
        hash[obj[:id]] = [obj[:data]]
      end
    end
    pp hash.to_a.map{|a| {id: a.first, data: a.last}}
    
[/code]


CC BY-SA 4.0
2018-11-11T14:43:52.767
50216
2018-11-11T14:43:52.767
30913
16749
answer


私も挑戦してみました。

[code]

    input = [
      {
        :id => 1,
        :data => 1
      },
      {
        :id => 1,
        :data => 2
      },
      {
        :id => 2,
        :data => 1
      },
      {
        :id => 2,
        :data => 2
      }
    ]
    
    output = input.reduce({}) { |hash, item|
      ( hash[item[:id]] ||= [] ) << item[:data]
      hash
    }.map { |key, value| { id: key, data: value } }
    
    pp output
    # => [{:id=>1, :data=>[1, 2]}, {:id=>2, :data=>[1, 2]}]
    
[/code]


CC BY-SA 4.0
2018-11-12T14:15:51.760
50258
2018-11-12T14:15:51.760
7900
16749
answer