【问题标题】:Ruby remove one nil element from array of hashesRuby 从哈希数组中删除一个 nil 元素
【发布时间】:2021-04-03 23:26:31
【问题描述】:

我有以下哈希数组:

[{:transaction_date=>nil, :net_amount=>100.0, :vat=>0.0},
 {:transaction_date=>nil, :net_amount=>100.0, :vat=>0.0},
 {:transaction_date=>nil, :net_amount=>100.0, :vat=>0.0},
 {:transaction_date=>"test", :net_amount=>100.0, :vat=>0.0}]

如何删除每个 transaction_date=>nil 的键和值 od 以获得如下内容:

[{:net_amount=>100.0, :vat=>0.0},
 {:net_amount=>100.0, :vat=>0.0},
 {:net_amount=>100.0, :vat=>0.0},
 {:transaction_date=>"test", :net_amount=>100.0, :vat=>0.0}]

我试图使用hash.select { |h| h[:transaction_date] },但我只得到:[{:transaction_date=>"test", :net_amount=>100.0, :vat=>0.0}] 结果。 compact也一样

【问题讨论】:

  • 如果您使用的是 ruby​​ >=2.4.6,您可以使用 arr.map {|hash| hash.compact } 或仅使用 arr.map(&:compact)。如果没有,您可以使用arr.map {|hash| hash.select {|_, v| !v.nil? } }。我建议检查this问题的第二个和第三个答案。
  • @Arun,请注意,如果该键的值为nil,则要排除的是键:transaction_date;不排除任何值为nil 的键。没错,它是示例中唯一值为 nil 的键,但将考虑限制在该键上是最安全的。
  • @CarySwoveland 好点。 @mr_muscle 如果您只想删除键为:transaction_date 且其值为nil 的条目,则可能需要使用arr.map {|hash| hash.select {|k, v| k != :transaction_date || !v.nil?}} 之类的东西。感谢@CarySwoveland 的评论!
  • 无关问题:语法{ :key => nil } 是否等同于{ key: nil }
  • @Fravadona:是的。

标签: ruby-on-rails ruby


【解决方案1】:

哈希有一个delete 方法,允许删除一个键。

a = {"a" => nil, "b" => 2} # => {"a"=>nil, "b"=>2}
a.delete("a") # => nil
a # => {"b"=>2}

然后您可以使用map 更改您的字段为 nil 的那些哈希。

a = [{:transaction_date=>nil, :net_amount=>100.0, :vat=>0.0},
     {:transaction_date=>nil, :net_amount=>100.0, :vat=>0.0}, 
     {:transaction_date=>nil, :net_amount=>100.0, :vat=>0.0}, 
     {:transaction_date=>"test", :net_amount=>100.0, :vat=>0.0}]
a.map do |h|
    h.delete(:transaction_date) if h[:transaction_date].nil?
    h
end # => => [{:net_amount=>100.0, :vat=>0.0}, {:net_amount=>100.0, :vat=>0.0}, {:net_amount=>100.0, :vat=>0.0}, {:transaction_date=>"test", :net_amount=>100.0, :vat=>0.0}]

【讨论】:

  • :transaction_date 如果h[:transaction_date] #=> false 将被删除,这不是所要求的。具体:h.delete(:transaction_date) if h[:transaction_date].nil?!如果不改变原始数组,请使用h.reject { |k,v| k==:transaction_date && v.nil? }
【解决方案2】:

首先,为什么要从哈希中删除:transaction_date?我可能是错的,但看起来稍后你最终会检查 :transaction_date 的值,如果是这样的话,我认为摆脱 :transaction_date 没有用,浪费了 CPU 周期。

您可以通过在需要访问h[:transaction_date]的地方执行以下操作来解决问题

if h[:transaction_date]
  # print/save/manipulate date
end

为什么?因为如果h[:transaction_date] 不存在于哈希中,那么当您稍后尝试访问它时,无论如何都会得到nil(除非您有默认值)。


Array#select 仅返回一个新数组,其中包含符合块标准的元素。如果该块返回错误的值,则传递给该块的元素将被丢弃。

这意味着你不能在这里有效地使用Array#select,因为你的元素是散列并且你想要的结果涉及每个散列的键。

Array#compact 返回一个删除了所有 nil 元素的新数组。同样,这只适用于数组级别,不会触及元素。

您尝试执行的操作与数组本身有关,而不是与数组的元素有关。

您需要检查数组的每个元素并根据您的标准修改它们。

有很多方法可以做到这一点,可能不是最好的,但这是一种方法:

arr.each do|h|
  if h[:transaction_date].nil?
    h.delete(:transaction_date)
  end
end

puts arr

【讨论】:

    【解决方案3】:

    如果值为 nil,这是从 has 中删除键的简单而简短的解决方案

    has_data = [{:transaction_date=>nil, :net_amount=>100.0, :vat=>0.0},
     {:transaction_date=>nil, :net_amount=>100.0, :vat=>0.0},
     {:transaction_date=>nil, :net_amount=>100.0, :vat=>0.0},
     {:transaction_date=>"test", :net_amount=>100.0, :vat=>0.0}]
    
    **has_data.each{|a| a.compact!}**
    

    【讨论】:

      【解决方案4】:

      如果只有transaction_date 可以为空,则可以只使用array_hash.map(&:compact)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-13
        • 2013-11-09
        • 1970-01-01
        • 2015-11-17
        • 1970-01-01
        • 2016-01-02
        • 2019-01-02
        相关资源
        最近更新 更多