Как я могу удалить все пустые элементы (пустые элементы списка) из вложенного файла Hash или YAML?
Удаление всех пустых элементов из хэша/YAML?
Ответ 1
Вы можете добавить компактный метод для Hash, как этот
class Hash
def compact
delete_if { |k, v| v.nil? }
end
end
или для версии, поддерживающей рекурсию
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
Ответ 2
Используйте hsh.delete_if. В вашем конкретном случае что-то вроде: hsh.delete_if { |k, v| v.empty? }
Ответ 3
Rails 4.1 добавлен Hash # compact и Хэш # 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
# => {}
Heads up: эта реализация не является рекурсивной. Как любопытство, они использовали его, используя #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
Ответ 4
Этот тоже удалит пустые хеши:
swoop = Proc.new { |k, v| v.delete_if(&swoop) if v.kind_of?(Hash); v.empty? }
hsh.delete_if &swoop
Ответ 5
Я знаю, что эта ветка немного устарела, но я придумал лучшее решение, которое поддерживает многомерные хэши. Он использует 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
Ответ 6
Вы можете использовать Hash # reject для удаления пустых пар ключ/значение из рубинового хэша.
# 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"}
Ответ 7
Я сделал для этого метод 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
Ответ 8
наша версия: он также очищает пустые строки и значения nil
class Hash
def compact
delete_if{|k, v|
(v.is_a?(Hash) and v.respond_to?('empty?') and v.compact.empty?) or
(v.nil?) or
(v.is_a?(String) and v.empty?)
}
end
end
Ответ 9
В Простой один вкладыш для удаления нулевых значений в Hash,
rec_hash.each {|key,value| rec_hash.delete(key) if value.blank? }
Ответ 10
Может быть сделано с facets библиотека (отсутствующие функции из стандартной библиотеки), например:
require 'hash/compact'
require 'enumerable/recursively'
hash.recursively { |v| v.compact! }
Работает с любым Enumerable (включая Array, Hash).
Посмотрите, как реализуется рекурсивный метод.
Ответ 11
Ruby Hash#compact
, Hash#compact!
и Hash#delete_if!
не работают с вложенными значениями nil
, empty?
и/или blank?
. Обратите внимание, что последние два метода являются деструктивными и что все значения nil
, ""
, false
, []
и {}
считаются blank?
.
Hash#compact
и Hash#compact!
доступны только в Rails или Ruby версии 2.4.0 и выше.
Здесь неразрушающее решение, которое удаляет все пустые массивы, хэши, строки и значения nil
, сохраняя все значения false
:
(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
Деструктивная версия:
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
Или, если вы хотите добавить обе версии в качестве методов экземпляра в классе 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
Другие параметры:
- Замените
v.blank? && v != false
наv.nil? || v == ""
, чтобы строго удалить пустые строки иnil
значения - Замените
v.blank? && v != false
наv.nil?
, чтобы строго удалить значенияnil
- Etc.
EDITED 2017/03/15 сохранить значения false
и представить другие параметры
Ответ 12
Я считаю, что было бы лучше использовать саморекурсивный метод. Таким образом, он идет настолько глубоко, насколько это необходимо. Это приведет к удалению пары значений ключа, если значение равно nil или пустой хэш.
class Hash
def compact
delete_if {|k,v| v.is_a?(Hash) ? v.compact.empty? : v.nil? }
end
end
Затем его использование будет выглядеть так:
x = {:a=>{:b=>2, :c=>3}, :d=>nil, :e=>{:f=>nil}, :g=>{}}
# => {:a=>{:b=>2, :c=>3}, :d=>nil, :e=>{:f=>nil}, :g=>{}}
x.compact
# => {:a=>{:b=>2, :c=>3}}
Чтобы сохранить пустые хеши, вы можете упростить это.
class Hash
def compact
delete_if {|k,v| v.compact if v.is_a?(Hash); v.nil? }
end
end
Ответ 13
class Hash
def compact
def _empty?(val)
case val
when Hash then val.compact.empty?
when Array then val.all? { |v| _empty?(v) }
when String then val.empty?
when NilClass then true
# ... custom checking
end
end
delete_if { |_key, val| _empty?(val) }
end
end
Ответ 14
Попробуйте удалить nil
hash = { a: true, b: false, c: nil }
=> {:a=>true, :b=>false, :c=>nil}
hash.inject({}){|c, (k, v)| c[k] = v unless v.nil?; c}
=> {:a=>true, :b=>false}