Ruby-on-rails 从哈希/YAML 中删除所有空元素?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3450641/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Removing all empty elements from a hash / YAML?
提问by Brian Jordan
How would I go about removing all empty elements (empty list items) from a nested Hash or YAML file?
我将如何从嵌套的 Hash 或 YAML 文件中删除所有空元素(空列表项)?
采纳答案by opsb
You could add a compact method to Hash like this
您可以像这样向 Hash 添加一个紧凑的方法
class Hash
def compact
delete_if { |k, v| v.nil? }
end
end
or for a version that supports recursion
或者对于支持递归的版本
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
回答by dgilperez
Rails 4.1 added Hash#compactand Hash#compact!as a core extensions to Ruby's Hashclass. You can use them like this:
Rails 4.1 添加了Hash#compact和Hash#compact!作为 RubyHash类的核心扩展。您可以像这样使用它们:
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
# => {}
Heads up: this implementation is not recursive. As a curiosity, they implemented it using #selectinstead of #delete_iffor performance reasons. See here for the benchmark.
注意:这个实现不是递归的。出于好奇,他们使用#select而不是#delete_if出于性能原因实现了它。请参阅此处了解基准。
In case you want to backport it to your Rails 3 app:
如果您想将其向后移植到您的 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
回答by jpemberthy
Use hsh.delete_if. In your specific case, something like: hsh.delete_if { |k, v| v.empty? }
使用hsh.delete_if。在您的具体情况下,例如:hsh.delete_if { |k, v| v.empty? }
回答by punund
This one would delete empty hashes too:
这个也会删除空哈希:
swoop = Proc.new { |k, v| v.delete_if(&swoop) if v.kind_of?(Hash); v.empty? }
hsh.delete_if &swoop
回答by Wilson Silva
If you're using Ruby 2.4+, you can call compactand compact!
如果您使用的是 Ruby 2.4+,则可以调用compact并compact!
h = { a: 1, b: false, c: nil }
h.compact! #=> { a: 1, b: false }
https://ruby-doc.org/core-2.4.0/Hash.html#method-i-compact-21
https://ruby-doc.org/core-2.4.0/Hash.html#method-i-compact-21
回答by smd1000
You can use Hash#rejectto remove empty key/value pairs from a ruby Hash.
您可以使用Hash#reject从 ruby 哈希中删除空的键/值对。
# 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"}
回答by srghma
works for both hashes and arrays
适用于散列和数组
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
P.S. based on someones answer, cant find
PS根据某人的回答,找不到
usage - Helpers::RecursiveCompact.recursive_compact(something)
用法 - Helpers::RecursiveCompact.recursive_compact(something)
回答by Sebastian Jay
Ruby's Hash#compact, Hash#compact!and Hash#delete_if!do not work on nested nil, empty?and/or blank?values. Note that the latter two methods are destructive, and that all nil, "", false, []and {}values are counted as blank?.
Ruby 的Hash#compact,Hash#compact!和Hash#delete_if!不适用于嵌套的nil,empty?和/或blank?值。请注意,后两种方法是破坏性的,并且所有nil,"",false,[]和{}的值都算作blank?。
Hash#compactand Hash#compact!are only available in Rails, or Ruby version 2.4.0 and above.
Hash#compact并且Hash#compact!仅在 Rails 或 Ruby 2.4.0 及更高版本中可用。
Here's a non-destructive solution that removes all empty arrays, hashes, strings and nilvalues, while keeping all falsevalues:
这是一个非破坏性解决方案,它删除所有空数组、散列、字符串和nil值,同时保留所有false值:
(blank?can be replaced with nil?or empty?as needed.)
(blank?可以根据需要替换nil?或替换empty?。)
def remove_blank_values(hash)
hash.each_with_object({}) do |(k, v), new_hash|
unless v.blank? && v != false
v.is_a?(Hash) ? new_hash[k] = remove_blank_values(v) : new_hash[k] = v
end
end
end
A destructive version:
破坏性版本:
def remove_blank_values!(hash)
hash.each do |k, v|
if v.blank? && v != false
hash.delete(k)
elsif v.is_a?(Hash)
hash[k] = remove_blank_values!(v)
end
end
end
Or, if you want to add both versions as instance methods on the Hashclass:
或者,如果您想将两个版本都添加为Hash类的实例方法:
class Hash
def remove_blank_values
self.each_with_object({}) do |(k, v), new_hash|
unless v.blank? && v != false
v.is_a?(Hash) ? new_hash[k] = v.remove_blank_values : new_hash[k] = v
end
end
end
def remove_blank_values!
self.each_pair do |k, v|
if v.blank? && v != false
self.delete(k)
elsif v.is_a?(Hash)
v.remove_blank_values!
end
end
end
end
Other options:
其他选项:
- Replace
v.blank? && v != falsewithv.nil? || v == ""to strictly remove empty strings andnilvalues - Replace
v.blank? && v != falsewithv.nil?to strictly removenilvalues - Etc.
- 更换
v.blank? && v != false用v.nil? || v == ""严格删除空字符串和nil值 - 更换
v.blank? && v != false用v.nil?严格除去nil值 - 等等。
EDITED 2017/03/15 to keep falsevalues and present other options
编辑 2017/03/15 以保持false价值并提供其他选项
回答by Kelly Becker
I know this thread is a bit old but I came up with a better solution which supports Multidimensional hashes. It uses delete_if? except its multidimensional and cleans out anything with a an empty value by default and if a block is passed it is passed down through it's children.
我知道这个线程有点旧,但我想出了一个支持多维哈希的更好的解决方案。它使用 delete_if? 除了它的多维并在默认情况下清除任何带有空值的东西,如果传递了一个块,它就会通过它的子代向下传递。
# Hash cleaner
class Hash
def clean!
self.delete_if do |key, val|
if block_given?
yield(key,val)
else
# Prepeare the tests
test1 = val.nil?
test2 = val === 0
test3 = val === false
test4 = val.empty? if val.respond_to?('empty?')
test5 = val.strip.empty? if val.is_a?(String) && val.respond_to?('empty?')
# Were any of the tests true
test1 || test2 || test3 || test4 || test5
end
end
self.each do |key, val|
if self[key].is_a?(Hash) && self[key].respond_to?('clean!')
if block_given?
self[key] = self[key].clean!(&Proc.new)
else
self[key] = self[key].clean!
end
end
end
return self
end
end
回答by mwalsher
I made a deep_compact method for this that recursively filters out nil records (and optionally, blank records as well):
我为此创建了一个 deep_compact 方法,它递归地过滤掉 nil 记录(以及可选的空白记录):
class Hash
# Recursively filters out nil (or blank - e.g. "" if exclude_blank: true is passed as an option) records from a Hash
def deep_compact(options = {})
inject({}) do |new_hash, (k,v)|
result = options[:exclude_blank] ? v.blank? : v.nil?
if !result
new_value = v.is_a?(Hash) ? v.deep_compact(options).presence : v
new_hash[k] = new_value if new_value
end
new_hash
end
end
end

