ruby 将在散列中找到的数组Map到各个散列值

0pizxfdo  于 2022-11-04  发布在  Ruby
关注(0)|答案(4)|浏览(128)

我从一个API获取数据,需要用不同的格式。我有一个car_array,它由一个哈希数组组成。但是,有时会有一个子数组作为哈希值之一,其中包含多个元素。在这种情况下,应该有一个循环,以便数组中的每个元素都正确地Map为单独的条目。
数据示例,请注意pricesoptions_package是多元素数组。

[{
  dealer_id: 1,
  dealer_name: "dealership 1",
  car_make: "jeep",
  prices: ['30', '32', '35'],
  options_package: ['A', 'B', 'C']
},  {
  dealer_id: 2,
  dealer_name: "dealership 2",
  car_make: "ford",
  prices: ['50', '55'],
  options_package: ['X', 'Y']
}, {
  dealer_id: 3,
  dealer_name: "dealership 3",
  car_make: "dodge",
  prices: ['70'],
  options_package: ['A']
}]

我想在有多个数组元素时创建多个条目
例如,上面的数据应分解并Map为:

some_array = [
  { dealer_id: 1, dealer_name: "dealership 1", car_make: "jeep",  price: '30', options_package: 'A' },
  { dealer_id: 1, dealer_name: "dealership 1", car_make: "jeep",  price: '32', options_package: 'B' },
  { dealer_id: 1, dealer_name: "dealership 1", car_make: "jeep",  price: '35', options_package: 'C' },
  { dealer_id: 2, dealer_name: "dealership 2", car_make: "ford",  price: '50', options_package: 'X' },
  { dealer_id: 2, dealer_name: "dealership 2", car_make: "ford",  price: '55', options_package: 'Y' },
  { dealer_id: 3, dealer_name: "dealership 3", car_make: "dodge", price: '70', options_package: 'A' }
]

这是我目前得到的结果:

car_arr.each do |car|
  if car['Prices'].length > 1
    # if there are multiple prices/options loop through each one and create a new car 
    car.each do |key, value|
      if key == 'Prices' 
        value.each do |price|
          formatted_car_array << { 
            dealer_id: car['dealer_id'], 
            dealer_name: car['dealer_name'], 
            car_make: car['make'], 
            options_package: ???????, 
            price: price, 
          }
        end
      end
    end                    
  else
    # there's only element for price and options_package 
    formatted_car_array << { 
      dealer_id: car['dealer_id'], 
      dealer_name: car['dealer_name'], 
      car_make: car['make'], 
      options_package: car['options_package'], 
      price: car['prices'] 
    }
  end
end
ufj5ltwl

ufj5ltwl1#

考虑从一个散列开始,以及如何解决这个更简单的问题。

h = {
  dealer_id: 1,
  dealer_name: "dealership 1",
  car_make: "jeep",
  prices: ['30', '32', '35'],
  options_package: ['A', 'B', 'C']
}

让我们使用#zip获得价格和选项包的组合。

h[:prices].zip(h[:options_package])

# => [["30", "A"], ["32", "B"], ["35", "C"]]

这个数组的长度3对应于我们期望从中得到多少个哈希值,所以让我们Map这些值,每次都构建一个新的哈希值。

h[:prices].zip(h[:options_package]).map do |price, pkg| 
  {
    dealer_id: h[:dealer_id],
    dealer_name: h[:dealer_name],
    car_make: h[:car_make],
    price: price,
    options_package: pkg,
  } 
end

# => [{:price=>"30", :options_package=>"A", :dealership=>nil, :dealer_id=>1, :car_make=>"jeep"},

# {:price=>"32", :options_package=>"B", :dealership=>nil, :dealer_id=>1, :car_make=>"jeep"},

# {:price=>"35", :options_package=>"C", :dealership=>nil, :dealer_id=>1, :car_make=>"jeep"}]

现在,您只需要在阵列上执行#flat_map操作即可。

car_arr.flat_map do |h|
  h[:prices].zip(h[:options_package]).map do |price, pkg| 
    {
      dealer_id: h[:dealer_id],
      dealer_name: h[:dealer_name],
      car_make: h[:car_make],
      price: price,
      options_package: pkg,
    } 
  end
end

# => [{:price=>"30", :options_package=>"A", :dealership=>nil, :dealer_id=>1, :car_make=>"jeep"},

# {:price=>"32", :options_package=>"B", :dealership=>nil, :dealer_id=>1, :car_make=>"jeep"},

# {:price=>"35", :options_package=>"C", :dealership=>nil, :dealer_id=>1, :car_make=>"jeep"},

# {:price=>"50", :options_package=>"X", :dealership=>nil, :dealer_id=>2, :car_make=>"ford"},

# {:price=>"55", :options_package=>"Y", :dealership=>nil, :dealer_id=>2, :car_make=>"ford"},

# {:price=>"70", :options_package=>"A", :dealership=>nil, :dealer_id=>3, :car_make=>"dodge"}]
ccrfmcuu

ccrfmcuu2#

如果arr是问题中给出的散列数组,则可以写如下。

arr.flat_map do |h|
  h[:prices].zip(h[:options_package]).map do |p,o|
    h.reject { |k,_| k == :prices }.merge(price: p, options_package: o)
  end
end
  #=> [{:dealer_id=>1, :dealer_name=>"dealership 1", :car_make=>"jeep",
  #     :options_package=>"A", :price=>"30"},
  #    {:dealer_id=>1, :dealer_name=>"dealership 1", :car_make=>"jeep",
  #     :options_package=>"B", :price=>"32"},
  #    {:dealer_id=>1, :dealer_name=>"dealership 1", :car_make=>"jeep",
  #     :options_package=>"C", :price=>"35"},
  #    {:dealer_id=>2, :dealer_name=>"dealership 2", :car_make=>"ford",
  #     :options_package=>"X", :price=>"50"},
  #    {:dealer_id=>2, :dealer_name=>"dealership 2", :car_make=>"ford",
  #     :options_package=>"Y", :price=>"55"},
  #    {:dealer_id=>3, :dealer_name=>"dealership 3", :car_make=>"dodge",
  #     :options_package=>"A", :price=>"70"}]

请注意,如果将键值对添加到散列中,或者删除或重命名键:dealer_id:dealer_name,则不需要更改此代码。

7fhtutme

7fhtutme3#

我的答案是answer of Chris上的扩展。

car_arr.flat_map do |h|
  h[:prices].zip(h[:options_package]).map do |price, pkg| 
    {
      dealer_id: h[:dealer_id],
      dealer_name: h[:dealer_name],
      car_make: h[:car_make],
      price: price,
      options_package: pkg,
    } 
  end
end

如果您使用的是最新的Ruby版本,这个答案可能会缩短。
Ruby 3.0引入了Hash#except,它可以让你轻松地创建一个没有指定键的哈希值的副本。

cars.flat_map do |car|
  car[:prices].zip(car[:options_package]).map do |price, pkg| 
    car.except(:prices).merge(price: price, options_package: pkg)
  end
end

car.except(:prices)将创建一个没有:prices键/值对的新散列,我们不需要移除:options_package,因为merge将用新值覆盖旧的:options_package值。
Ruby 3.1引入了{ x:, y: }作为{ x: x, y: y }的语法糖。这允许我们进一步“简化”答案:

cars.flat_map do |car|
  car[:prices].zip(car[:options_package]).map do |price, options_package| 
    car.except(:prices).merge(price:, options_package:)
  end
end
rhfm7lfc

rhfm7lfc4#

输入

input = [{
       dealer_id: 1,
       dealer_name: "dealership 1",
       car_make: "jeep",
       prices: ['30', '32', '35'],
       options_package: ['A', 'B', 'C']
     }, {
       dealer_id: 2,
       dealer_name: "dealership 2",
       car_make: "ford",
       prices: ['50', '55'],
       options_package: ['X', 'Y']
     }, {
       dealer_id: 3,
       dealer_name: "dealership 3",
       car_make: "dodge",
       prices: ['70'],
       options_package: ['A']
     }]

编码

result = input.map do |h|
  prices = h[:prices]
  options_package = h[:options_package]
  h[:options_package].count.times.map do
    h[:prices] = prices.shift
    h[:options_package] = options_package.shift
    h.dup
  end
end

p result.flatten

输出量

[{:dealer_id=>1, :dealer_name=>"dealership 1", :car_make=>"jeep", :prices=>"30", :options_package=>"A"}, 
 {:dealer_id=>1, :dealer_name=>"dealership 1", :car_make=>"jeep", :prices=>"32", :options_package=>"B"}, 
 {:dealer_id=>1, :dealer_name=>"dealership 1", :car_make=>"jeep", :prices=>"35", :options_package=>"C"}, 
 {:dealer_id=>2, :dealer_name=>"dealership 2", :car_make=>"ford", :prices=>"50", :options_package=>"X"}, 
 {:dealer_id=>2, :dealer_name=>"dealership 2", :car_make=>"ford", :prices=>"55", :options_package=>"Y"}, 
 {:dealer_id=>3, :dealer_name=>"dealership 3", :car_make=>"dodge", :prices=>"70", :options_package=>"A"}]

相关问题