Удалить все пустые элементы из хэша / YAML? - PullRequest
124 голосов
/ 10 августа 2010

Как мне удалить все пустые элементы (пустые элементы списка) из вложенного файла Hash или YAML?

Ответы [ 17 ]

2 голосов
/ 28 сентября 2016

Может быть сделано с библиотекой facets (отсутствует в стандартной библиотеке), например:

require 'hash/compact'
require 'enumerable/recursively'
hash.recursively { |v| v.compact! }

Работает с любым Enumerable (включая Array, Hash).

Посмотрите, как реализован рекурсивный метод .

2 голосов
/ 09 ноября 2013

наша версия: он также очищает пустые строки и значения 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
0 голосов
/ 16 апреля 2019

Вот что у меня есть:

# recursively remove empty keys (hashes), values (array), hashes and arrays from hash or array
def sanitize data
  case data
  when Array
    data.delete_if { |value| res = sanitize(value); res.blank? }
  when Hash
    data.delete_if { |_, value| res = sanitize(value); res.blank? }
  end
  data.blank? ? nil : data
end
0 голосов
/ 28 декабря 2018

Рекурсивная версия https://stackoverflow.com/a/14773555/1519240 работает, но не с HashWithIndifferentAccess или другими классами типа Hash.

Вот версия, которую я использую:

def recursive_compact
  inject({}) do |new_hash, (k,v)|
    if !v.nil?
      new_hash[k] = v.kind_of?(Hash) ? v.recursive_compact : v
    end
    new_hash
  end
end

kind_of?(Hash) будет принимать больше классов, похожих на хэш.

Вы также можете заменить inject({}) на inject(HashWithIndifferentAccess.new), если хотите получить доступ к новому хешу, используя как символ, так и строку.

0 голосов
/ 20 апреля 2017

Попробуйте удалить 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}
0 голосов
/ 14 июля 2016
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
0 голосов
/ 13 февраля 2015

Я считаю, что было бы лучше использовать саморекурсивный метод. Таким образом, он идет так глубоко, как необходимо. Это удалит пару ключ-значение, если значение равно нулю или пустой хэш.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...