Объединить один массив во вложенный массив в рельсах - PullRequest
0 голосов
/ 10 октября 2019

У меня есть список объектов примерно так:

      a = [
          {
              id: 0,
              name: "ABC",
              work: "ABC2"
          },
          {
              id: 0,
              name: "XYZ",
              work: "XYZ2"
          },
          {
              id: 1,
              name: "ACD",
              work: "ACD2"
          }
      ]

И я хочу преобразовать его во что-то вроде этого:

      b = [
            {
              id: 0,
              fields: [
                  {
                    name: "ABC",
                    work: "ABC2"
                  },
                  {
                    name: "XYZ",
                    work: "XYZ2"
                  }
                ]
            },

            {
                id: 1,
                fields: [
                    {
                        name: "ACD",
                        work: "ACD2"
                    }
                ]
            }
      ]

Идея состоит в том, чтобы сгруппировать объекты (по идентификатору) в одном массиве.

Подход, который я пробовал:

      b = []

      rest_object = []

      a.each_with_index do |aa, idx|

        aa.delete(:id)

        rest_object << aa

        if idx == 0
          next
        end

        puts a[idx][:id], a[idx-1][:id]

        if a[idx][:id] != a[idx-1][:id]
          b << {id: a[idx-1][:id], names: rest_object}
          rest_object = []
        end

      end

Но я получаю пустой вывод.

Кроме того, если возможно достичьто же самое в некотором роде. Это было бы полезно.

Ответы [ 4 ]

1 голос
/ 10 октября 2019

Что-то вроде этого делает работу. Это удаляет пару ключ-значение :id из каждого хэша и использует значение для group оставшейся части хэша. Затем map результирующий хеш для создания массива и преобразования данных в формат {id: ..., fields: ...}.

a = [{id: 0, name: "ABC", work: "ABC2"}, {id: 0, name: "XYZ", work: "XYZ2"}, {id: 1, name: "ACD", work: "ACD2"}]

b = a.group_by { |hash| hash.delete(:id) }
     .map { |id, fields| {id: id, fields: fields} }
#=> [{:id=>0, :fields=>[{:name=>"ABC", :work=>"ABC2"}, {:name=>"XYZ", :work=>"XYZ2"}]}, {:id=>1, :fields=>[{:name=>"ACD", :work=>"ACD2"}]}]

Примечание: Это мутирует хэши в a массив. Если вы не хотите это изменение a.group_by на a.map(&:dup).group_by. Который сначала дублирует все хэши перед выполнением любых мутаций.

0 голосов
/ 10 октября 2019
  a = [
      {
          id: 0,
          name: "ABC"
      },
      {
          id: 0,
          name: "XYZ"
      },
      {
          id: 1,
          name: "ACD"
      }
  ]

ary = []
a.each do|val|
 ary[val[:id]] = {id: val[:id]} unless ary[val[:id]] 
 ary[val[:id]][:names] = [] unless ary[val[:id]][:names]
 ary[val[:id]][:names].push({name: val[:name]})
end
0 голосов
/ 10 октября 2019

Если я понимаю, учитывая более общий массив, подобный этому:

a = [ { id: 0, name: "ABC", etc: "01" },
      { id: 0, name: "XYZ", etc: "02" },
      { id: 1, name: "ACD", etc: "11" } ]

Первая идея, которая мне пришла в голову, заключается в следующем:

require 'active_support/inflector' # for using pluralize

res = a.group_by{ |h| h[:id] }.values.map do |ary|
        h = Hash.new{ |h,k| h[k] = [] }
        ary.each { |hh| hh.each { |k,v| h[k] << v } }
        h[:id] = h[:id].first
        h.transform_keys do |k|
          unless k == :id
            k.to_s.pluralize.to_sym
          else
            k
          end
        end
      end

res #=> [{:id=>0, :names=>["ABC", "XYZ"], :etcs=>["01", "02"]}, {:id=>1, :names=>["ACD"], :etcs=>["11"]}]

Это не совсем тактребуемый формат, но чтобы получить этот формат, просто измените эту строку

ary.each { |hh| hh.each { |k,v| h[k] << v } }

на

ary.each { |hh| hh.each { |k,v| h[k] << { k => v } } }
0 голосов
/ 10 октября 2019

Попробуйте следующее,

required_keys = a[0].except(:id).keys
b = a.group_by { |x| x[:id] }

b = b.inject([]) do |m,(k,v)|
      arr =  { id: k }
      required_keys.each do |key|
        arr[key.to_s.pluralize.to_sym] = v.map { |z| z.slice(key) }
      end
      m << arr
    end

# => [{:id=>0, :names=>[{:name=>"ABC"}, {:name=>"XYZ"}]}, {:id=>1, :names=>[{:name=>"ACD"}]}]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...