如何从返回的数组中删除带有nil值的额外数组级别

时间:2018-10-23 11:31:51

标签: arrays ruby hash

我有几乎是 的这段代码,可以给我我想要的东西。

def merge_data(keys, data)

merged_data = keys.map {|hash| data.first.map {|k,v| if hash.values.first == k then hash.merge(v) end}}

end

有关预期(第一个)和实际返回值之间的差异,请参见下文:

-[{:awesomeness=>10,
   -  :first_name=>"blake",
   -  :height=>"74",
   -  :last_name=>"johnson"},
   - {:awesomeness=>9, :first_name=>"ashley", :height=>60, :last_name=>"dubs"}]

   +[[{:awesomeness=>10,
   +   :first_name=>"blake",
   +   :height=>"74",
   +   :last_name=>"johnson"},
   +  nil],
   + [nil,
   +  {:awesomeness=>9, :first_name=>"ashley", :height=>60, :last_name=>"dubs"}]]

如果有人可以解释为什么我得到的索引为nil的额外数组级别,将不胜感激!

基于以下数据:

let(:keys) {[
       {:first_name => "blake"},
       {:first_name => "ashley"}
]}

  let(:data) {[
       {"blake" => {
            :awesomeness => 10,
                 :height => "74",
              :last_name => "johnson"},
        "ashley" => {
            :awesomeness => 9,
                 :height => 60,
              :last_name => "dubs"}
    }
 ]}

  let(:merged_data) {[
       {:first_name => "blake",
        :awesomeness => 10,
             :height => "74",
          :last_name => "johnson"},

       {:first_name => "ashley",
        :awesomeness => 9,
             :height => 60,
          :last_name => "dubs"}
]}

谢谢!

3 个答案:

答案 0 :(得分:0)

您快到了,只需要进行微调:

def merge_data(keys, data)
  merged_data = keys.map {|hash| data.first.map {|k,v| if hash.values.first == k then hash.merge(v) end }.compact[0] }
end

keys = [{:first_name => "blake"}, {:first_name => "ashley"}]

data = [
  {"blake" => {
       :awesomeness => 10,
            :height => "74",
         :last_name => "johnson"},
   "ashley" => {
       :awesomeness => 9,
            :height => 60,
         :last_name => "dubs"}
  }]

puts  merge_data(keys, data).inspect

#=>
[ 
  {
    :first_name=>"blake",
    :awesomeness=>10,
    :height=>"74",
    :last_name=>"johnson"},
  {
    :first_name=>"ashley",
    :awesomeness=>9,
    :height=>60,
    :last_name=>"dubs"
  }
]

更改了什么?

在内部块中添加了.compact[0]

为什么?因为它是在每个键和每个数据值上运行的map。对于与另一个不匹配的一个返回nil,并且每次返回一个数组而不是Hash对象。

但是,我们可以创建一个自定义类并在以后重建数据:

class Person
  attr_reader :first_name, :last_name, :height, :awesomeness
  def initialize(first_name)
    @first_name = first_name
  end

  def update(info)
    info.each do |key, value|
      instance_variable_set("@#{key}", value) if respond_to?(key)
    end
  end

  def to_h
    { first_name: self.first_name, last_name: self.last_name, awesomeness: self.awesomeness, height: self.height }
  end
end

people = keys.each_with_object({}) do |k, person_map|
  person_map[k[:first_name]] = Person.new(k[:first_name])
end

data.each do |people_info|
  people_info.each do |first_name, info|
    if people[first_name]
      people[first_name].update(info)
    end
  end
end

p people.values.map{ |p| p.to_h }

#=> [{:first_name=>"blake", :last_name=>"johnson", :awesomeness=>10, :height=>"74"}, {:first_name=>"ashley", :last_name=>"dubs", :awesomeness=>9, :height=>60}]

答案 1 :(得分:0)

给出数据集:

data = {
        "blake" => {
            :awesomeness => 10,
                 :height => "74",
              :last_name => "johnson"},
        "ashley" => {
            :awesomeness => 9,
                 :height => 60,
              :last_name => "dubs"}
        }

为什么不像这样?

data.map { |h| h.last.merge({first_name: h.first}) }

#=> [{:awesomeness=>10, :height=>"74", :last_name=>"johnson", :first_name=>"blake"}, {:awesomeness=>9, :height=>60, :last_name=>"dubs", :first_name=>"ashley"}]


编辑

因此,如果我很了解您的数据结构,请尝试Enumerable#each_with_object

def merge_data(keys, data)
  keys.each_with_object([]) { |hash, obj| data.first.map { |k,v| if hash.values.first == k then obj << hash.merge(v) end } }
end

keys = [
         {:first_name => "blake"},
         {:first_name => "ashley"}
       ]

data = [{
        "blake" => {
            :awesomeness => 10,
            :height => "74",
            :last_name => "johnson"},
        "ashley" => {
            :awesomeness => 9,
            :height => 60,
            :last_name => "dubs"}
        }]

merge_data(keys, data)

#=> [{:first_name=>"blake", :awesomeness=>10, :height=>"74", :last_name=>"johnson"}, {:first_name=>"ashley", :awesomeness=>9, :height=>60, :last_name=>"dubs"}]

答案 2 :(得分:0)

keys = [{ :first_name=> "ashley" }, { :first_name=>"blake" }]    
data = [{ "blake"  => { :awesomeness=>10, :height=>"74", :last_name=>"johnson" },
          "margo"  => { :awesomeness=>30, :height=>"63", :last_name=>"magpie"  },
          "ashley" => { :awesomeness=>9,  :height=>"60", :last_name=>"dubs"    } }]

我建议分两个步骤进行。首先是为data的内容构造一个更合适的数据结构,即哈希:

data_adj = data.reduce(&:merge)
   #=> {"blake" =>{:awesomeness=>10, :height=>"74", :last_name=>"johnson"},
   #    "margo" =>{:awesomeness=>30, :height=>"63", :last_name=>"magpie"},
   #    "ashley"=>{:awesomeness=>9,  :height=>"60", :last_name=>"dubs"}}

第二个方法是将keys中的哈希值与data_adj的适当值合并:

keys.map { |h| h.merge(data_adj[h[:first_name]]) }
  #=> [{:first_name=>"ashley", :awesomeness=>9,  :height=>"60", :last_name=>"dubs"},
  #    {:first_name=>"blake",  :awesomeness=>10, :height=>"74", :last_name=>"johnson"}]

如果要针对keys的不同值重复执行合并操作,则此方法将特别有效,因为data_adj仅需要计算一次。将问题分为两个也可以加快测试速度。