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

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

Ответы [ 17 ]

137 голосов
/ 10 августа 2010

Использовать hsh.delete_if .В вашем конкретном случае что-то вроде: hsh.delete_if { |k, v| v.empty? }

136 голосов
/ 23 августа 2014

Rails 4.1 добавлено Hash # compact и Hash # compact! в качестве основных расширений для класса 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: эта реализация не является рекурсивной.Любопытно, что они реализовали это, используя #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
67 голосов
/ 08 февраля 2013

Вы можете добавить компактный метод в 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
7 голосов
/ 28 февраля 2012

Это тоже удалит пустые хэши:

swoop = Proc.new { |k, v| v.delete_if(&swoop) if v.kind_of?(Hash);  v.empty? }
hsh.delete_if &swoop
5 голосов
/ 17 февраля 2016

Вы можете использовать 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"}
5 голосов
/ 11 сентября 2012

Я знаю, что этот поток немного староват, но я нашел лучшее решение, которое поддерживает многомерные хеши.Он использует delete_if?кроме его многомерного и очищает все с пустым значением по умолчанию, и если блок передается, он передается через его потомков.

4 голосов
/ 07 апреля 2015

Я создал для этого метод deep_compact, который рекурсивно отфильтровывает ноль записей (и, необязательно, пустые записи):

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
4 голосов
/ 22 мая 2018

работает как для хэшей, так и для массивов

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

PS на основе чьего-либо ответа, не могу найти

использование - Helpers::RecursiveCompact.recursive_compact(something)

4 голосов
/ 14 марта 2017

Ruby's 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 значений
  • И т.д.

РЕДАКТИРОВАНИЕ 2017/03 /15, чтобы сохранить false значения и представить другие параметры

3 голосов
/ 29 октября 2014

В Simple one liner для удаления нулевых значений в Hash,

rec_hash.each {|key,value| rec_hash.delete(key) if value.blank? } 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...