如何将散列数组从值转换为带键的散列对象?

时间:2023-01-01 12:42:23

How to create hash object with keys created from values and grouped by them?

如何使用从值创建并按值分组的键创建散列对象?

cars = [{
  id: 1,
  properties: {
    name: "audi",
    type: "petrol"
  },
},{
  id: 1,
  properties: {
    name: "ford",
    type: "petrol"
  }
},{
  id: 1,
  properties: {
    name: "tesla",
    type: "electric"
  }
}]

Desired effect:

预期效果:

{
  petrol: [{name: "audi"}, {name: "ford"}],
  electric: [{name: "tesla"}]
}

My current function gives desired effect but it is too long, How can I get the same effect with shorter code?

我的当前函数给出了期望的效果,但是它太长了,我怎么才能用更短的代码获得同样的效果呢?

cars.map { |c| Hash[c[:properties][:type], c[:properties][:name]] }.group_by{|h| h.keys.first}.each_value{|a| a.map!{|h| h.values.first}}

4 个解决方案

#1


4  

I came up with something like this. The grouped_cars variable should be extracted to a separate method.

我想到了这样的东西。grouped_cars变量应该被提取到一个单独的方法中。

grouped_cars = cars.inject({}) do |result, car|
  result[car[:properties][:type]] ||= []
  result[car[:properties][:type]] << { name: car[:properties][:name] }
  result
end

{ cars: grouped_cars }

#2


2  

My variant:

我的版本:

{
  cars: cars.inject({}) do |hash, data|
      type, name = data[:properties].values_at(:type, :name)
      hash[type] ||= []
      hash[type] << {name: name}
      hash
    end
}

And even shorter:

甚至更短:

{
  cars: cars.inject(Hash.new([])) do |hash, car|
      type, name = car[:properties].values_at(:type, :name);
      hash[type] += [{ name: name }];
      hash
    end
}

#3


2  

inject method have to return the memo each time, I think each_with_object is better.

注入方法每次都要返回memo,我认为each_with_object更好。

cars.each_with_object({}) do |item, hash|
  (hash[item[:properties][:type]] ||= []) << { name: item[:properties][:name] }
end

=> {"petrol"=>[{:name=>"audi"}, {:name=>"ford"}], "electric"=>[{:name=>"tesla"}]}

#4


0  

I suggest the following:

我建议以下几点:

cars.map { |h| h[:properties] }.each_with_object({}) { |g,h|
  h.update(g[:type]=>[{ name: g[:name] }]) { |_,o,n| {name: o+n } } }
  #=> {"petrol"=>{:name=>[{:name=>"audi"}, {:name=>"ford"}]},
  #    "electric"=>[{:name=>"tesla"}]}  

Firstly, we obtain:

首先,我们得到:

cars.map { |h| h[:properties] }
  #=> [{:name=>"audi",  :type=>"petrol"},
  #    {:name=>"ford",  :type=>"petrol"},
  #    {:name=>"tesla", :type=>"electric"}]

We then use the form of Hash#update (aka merge!) that uses the block:

然后我们使用Hash#update(又名merge!)的形式,使用block:

{ |_,o,n| { name: o+n } }

to determine the values of keys that are present in both hashes being merged.

确定合并的两个散列中存在的键的值。

Initially, the hash:

最初,该散列:

{ "petrol"=>[{ :name=>"audi"] }] }

is merged into an empty hash represented by the block variable h. This merge does not make use of the block because h is empty and therefore does not have a key "petrol".

合并到由块变量h表示的空散列中。这种合并不会使用块,因为h是空的,因此没有键“汽油”。

Next, the hash:

接下来,散列:

{ "petrol"=>[{ :name=>"ford" }] }

is merged into h. Since both this hash and h have keys "petrol", the value of "petrol" is given by the block:

由于这个散列和h都有“汽油”键,所以block给出“汽油”的值:

{ |_,o,n| { name: o+n } }
  #=> {|_,[{ :name=>"audi" }] , [{ :name=>"ford" }]| 
  #      [{ name: "audi" }] + [{ name: "ford" }] }
  #=> [{ name: "audi" }, { name: "ford" }]

Lastly, the hash:

最后,哈希:

{ "electric"=>{ :name=>"tesla" } }

is merged into h. Since h does not have a key "electric", the block is not not needed to determine the value of that key.

由于h没有键“electric”,所以不需要块来确定键的值。

#1


4  

I came up with something like this. The grouped_cars variable should be extracted to a separate method.

我想到了这样的东西。grouped_cars变量应该被提取到一个单独的方法中。

grouped_cars = cars.inject({}) do |result, car|
  result[car[:properties][:type]] ||= []
  result[car[:properties][:type]] << { name: car[:properties][:name] }
  result
end

{ cars: grouped_cars }

#2


2  

My variant:

我的版本:

{
  cars: cars.inject({}) do |hash, data|
      type, name = data[:properties].values_at(:type, :name)
      hash[type] ||= []
      hash[type] << {name: name}
      hash
    end
}

And even shorter:

甚至更短:

{
  cars: cars.inject(Hash.new([])) do |hash, car|
      type, name = car[:properties].values_at(:type, :name);
      hash[type] += [{ name: name }];
      hash
    end
}

#3


2  

inject method have to return the memo each time, I think each_with_object is better.

注入方法每次都要返回memo,我认为each_with_object更好。

cars.each_with_object({}) do |item, hash|
  (hash[item[:properties][:type]] ||= []) << { name: item[:properties][:name] }
end

=> {"petrol"=>[{:name=>"audi"}, {:name=>"ford"}], "electric"=>[{:name=>"tesla"}]}

#4


0  

I suggest the following:

我建议以下几点:

cars.map { |h| h[:properties] }.each_with_object({}) { |g,h|
  h.update(g[:type]=>[{ name: g[:name] }]) { |_,o,n| {name: o+n } } }
  #=> {"petrol"=>{:name=>[{:name=>"audi"}, {:name=>"ford"}]},
  #    "electric"=>[{:name=>"tesla"}]}  

Firstly, we obtain:

首先,我们得到:

cars.map { |h| h[:properties] }
  #=> [{:name=>"audi",  :type=>"petrol"},
  #    {:name=>"ford",  :type=>"petrol"},
  #    {:name=>"tesla", :type=>"electric"}]

We then use the form of Hash#update (aka merge!) that uses the block:

然后我们使用Hash#update(又名merge!)的形式,使用block:

{ |_,o,n| { name: o+n } }

to determine the values of keys that are present in both hashes being merged.

确定合并的两个散列中存在的键的值。

Initially, the hash:

最初,该散列:

{ "petrol"=>[{ :name=>"audi"] }] }

is merged into an empty hash represented by the block variable h. This merge does not make use of the block because h is empty and therefore does not have a key "petrol".

合并到由块变量h表示的空散列中。这种合并不会使用块,因为h是空的,因此没有键“汽油”。

Next, the hash:

接下来,散列:

{ "petrol"=>[{ :name=>"ford" }] }

is merged into h. Since both this hash and h have keys "petrol", the value of "petrol" is given by the block:

由于这个散列和h都有“汽油”键,所以block给出“汽油”的值:

{ |_,o,n| { name: o+n } }
  #=> {|_,[{ :name=>"audi" }] , [{ :name=>"ford" }]| 
  #      [{ name: "audi" }] + [{ name: "ford" }] }
  #=> [{ name: "audi" }, { name: "ford" }]

Lastly, the hash:

最后,哈希:

{ "electric"=>{ :name=>"tesla" } }

is merged into h. Since h does not have a key "electric", the block is not not needed to determine the value of that key.

由于h没有键“electric”,所以不需要块来确定键的值。