从哈希/ YAML中删除所有空元素?

Bri*_*dan 129 ruby hash yaml ruby-on-rails

我如何从嵌套的Hash或YAML文件中删除所有空元素(空列表项)?

dgi*_*rez 146

Rails 4.1添加了Hash#compactHash#compact!作为Ruby Hash类的核心扩展.您可以像这样使用它们:

hash = { a: true, b: false, c: nil }
hash.compact                        
# => { a: true, b: false }
hash                                
# => { a: true, b: false, c: nil }
hash.compact!                        
# => { a: true, b: false }
hash                                
# => { a: true, b: false }
{ c: nil }.compact                  
# => {}
Run Code Online (Sandbox Code Playgroud)

抬头:这个实现不是递归的.作为一种好奇心,他们使用#select而不是#delete_if出于性能原因来实现它.请参阅此处获取基准.

如果你想将它反向移植到你的Rails 3应用程序:

# config/initializers/rails4_backports.rb

class Hash
  # as implemented in Rails 4
  # File activesupport/lib/active_support/core_ext/hash/compact.rb, line 8
  def compact
    self.select { |_, value| !value.nil? }
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 很好,整洁,但可能值得注意的是,与接受的答案不同,Rails扩展不是递归的? (3认同)
  • 它省略了空散列。 (2认同)

jpe*_*thy 138

使用hsh.delete_if.在您的具体情况下,例如:hsh.delete_if { |k, v| v.empty? }

  • 递归的:`proc = Proc.new {| k,v | v.kind_of?(哈希)?(v.delete_if(&l); nil):v.empty?}; hsh.delete_if(PROC)` (6认同)
  • 你可以使用.delete_if {| k,v | v.blank?} (6认同)
  • 我相信你的答案是正确的:proc = Proc.new {| k,v | v.kind_of?(哈希)?(v.delete_if(&proc); nil):v.empty?}; hsh.delete_if(PROC) (3认同)
  • @BSeven似乎他们听到了你的声音!http://api.rubyonrails.org/classes/Hash.html#method-i-compact(Rails 4.1) (3认同)
  • 如果`v`为nil,这将抛出一个'NoMethodError`. (2认同)

ops*_*psb 70

您可以像这样向Hash添加一个紧凑的方法

class Hash
  def compact
    delete_if { |k, v| v.nil? }
  end
end
Run Code Online (Sandbox Code Playgroud)

或者支持递归的版本

class Hash
  def compact(opts={})
    inject({}) do |new_hash, (k,v)|
      if !v.nil?
        new_hash[k] = opts[:recurse] && v.class == Hash ? v.compact(opts) : v
      end
      new_hash
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 请注意`compact` 和`compact!` 是Ruby => 2.4.0 和Rails => 4.1 的标准。虽然它们是非递归的。 (5认同)
  • 紧凑应该只删除nils.不是虚假的价值观 (2认同)
  • 这有一个问题:`Hash#delete_if` 是一种破坏性操作,而`compact` 方法不会修改对象。您可以使用`Hash#reject`。或者调用方法`Hash#compact!`。 (2认同)

Mar*_*n13 13

compact_blank (Rails 6.1+)

如果您使用Rails(或独立ActiveSupport),从 version 开始6.1,有一种compact_blank方法可以blank从散列中删除值。

Object#blank?在引擎盖下用于确定项目是否为空白。

{ a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
# => { b: 1, f: true }
Run Code Online (Sandbox Code Playgroud)

这是文档链接和相关 PR链接

还可以使用破坏性变体。见Hash#compact_blank!


如果您只需要删除nil值,

请考虑使用 Ruby 内置Hash#compactHash#compact!方法。

{ a: 1, b: false, c: nil }.compact
# => { a: 1, b: false }
Run Code Online (Sandbox Code Playgroud)


Wil*_*lva 12

如果您使用的是 Ruby 2.4+,则可以调用compactcompact!

h = { a: 1, b: false, c: nil }
h.compact! #=> { a: 1, b: false }
Run Code Online (Sandbox Code Playgroud)

https://ruby-doc.org/core-2.4.0/Hash.html#method-i-compact-21


pun*_*und 7

这个也会删除空哈希:

swoop = Proc.new { |k, v| v.delete_if(&swoop) if v.kind_of?(Hash);  v.empty? }
hsh.delete_if &swoop
Run Code Online (Sandbox Code Playgroud)


das*_*vvv 5

您可以使用Hash#reject从ruby Hash中删除空键/值对.

# Remove empty strings
{ a: 'first', b: '', c: 'third' }.reject { |key,value| value.empty? } 
#=> {:a=>"first", :c=>"third"}

# Remove nil
{a: 'first', b: nil, c: 'third'}.reject { |k,v| v.nil? } 
# => {:a=>"first", :c=>"third"}

# Remove nil & empty strings
{a: '', b: nil, c: 'third'}.reject { |k,v| v.nil? || v.empty? } 
# => {:c=>"third"}
Run Code Online (Sandbox Code Playgroud)

  • FYI:`.empty?`引发数字错误,所以你可以在`Rails`中使用`.blank?` (3认同)

srg*_*hma 5

适用于散列和数组

module Helpers
  module RecursiveCompact
    extend self

    def recursive_compact(hash_or_array)
      p = proc do |*args|
        v = args.last
        v.delete_if(&p) if v.respond_to? :delete_if
        v.nil? || v.respond_to?(:"empty?") && v.empty?
      end

      hash_or_array.delete_if(&p)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

PS根据某人的回答,找不到

用法 - Helpers::RecursiveCompact.recursive_compact(something)