prosource

해시/AML에서 모든 빈 요소를 제거하시겠습니까?

probook 2023. 6. 2. 20:36
반응형

해시/AML에서 모든 빈 요소를 제거하시겠습니까?

중첩된 해시 또는 YAML 파일에서 모든 빈 요소(빈 목록 항목)를 제거하려면 어떻게 해야 합니까?

Rails 4.1은 Ruby의 핵심 확장으로 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                  
# => {}

주의: 이 구현은 재귀적이지 않습니다.호기심으로, 그들은 다음을 사용하여 구현했습니다.#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

hsh.delete_if를 사용합니다.구체적인 경우 다음과 같은 것이 있습니다.hsh.delete_if { |k, v| v.empty? }

이렇게 해시에 압축 메서드를 추가할 수 있습니다.

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

compact_blank(레일 6.1+)

사용 중인 경우Rails(또는 독립 실행형)ActiveSupport), 버전부터 시작6.1을 제거하는 방법이 있습니다.blank해시 값입니다.

후드 아래를 사용하여 항목이 비어 있는지 확인합니다.

{ a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
# => { b: 1, f: true }

문서에 대한 링크관련 PR에 대한 링크입니다.

파괴적인 변형도 사용할 수 있습니다.참조.


제거만 필요한 경우nil가치,

루비 빌트인과 메소드를 사용하는 것을 고려해 주십시오.

{ a: 1, b: false, c: nil }.compact
# => { a: 1, b: false }

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

이것도 빈 해시를 삭제합니다.

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

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"}

해시 및 어레이 모두에 사용 가능

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

누군가의 대답에 근거한 추신: 찾을 수 없습니다.

용도 -Helpers::RecursiveCompact.recursive_compact(something)

이 스레드가 약간 오래된 것은 알지만 다차원 해시를 지원하는 더 나은 솔루션을 생각해냈습니다.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

이를 위해 제로 레코드(및 선택적으로 빈 레코드)를 재귀적으로 필터링하는 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

루비의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/false하고 기타 을 표시합니다.

우리 버전: 빈 문자열과 0 값도 정리합니다.

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

해시에서 null 값을 삭제하는 단순 하나의 라이너에서

rec_hash.each {|key,value| rec_hash.delete(key) if value.blank? } 

다음과 같이 패싯 라이브러리(표준 라이브러리에서 누락된 기능)로 수행할 수 있습니다.

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

모든 열거형(어레이, 해시 포함)과 함께 작동합니다.

재귀적 방법이 구현되는 방식을 확인합니다.

https://stackoverflow.com/a/14773555/1519240 의 재귀 버전은 작동하지만 다음 버전에서는 작동하지 않습니다.HashWithIndifferentAccess아니면 해시 같은 다른 수업들..

사용 중인 버전은 다음과 같습니다.

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)해시와 같은 클래스를 더 많이 허용합니다.

▁also▁you를 대체할 수도 있습니다.inject({})타고inject(HashWithIndifferentAccess.new)기호와 문자열을 모두 사용하여 새 해시에 액세스하려는 경우.

저는 자기 재귀적인 방법을 사용하는 것이 가장 좋을 것이라고 생각합니다.그렇게 하면 필요한 만큼 깊이 들어갈 수 있습니다.값이 0이거나 비어 있는 해시일 경우 키 값 쌍이 삭제됩니다.

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
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을(를) 제거합니다.

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}

제가 가진 것은 다음과 같습니다.

# 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

해시에서 완전 삭제 nil 값입니다.

  # returns new instance of hash with deleted nil values
  def self.deep_remove_nil_values(hash)
    hash.each_with_object({}) do |(k, v), new_hash|
      new_hash[k] = deep_remove_nil_values(v) if v.is_a?(Hash)
      new_hash[k] = v unless v.nil?
    end
  end

  # rewrite current hash
  def self.deep_remove_nil_values!(hash)
    hash.each do |k, v|
      deep_remove_nil_values(v) if v.is_a?(Hash)
      hash.delete(k) if v.nil?
    end
  end

2 루비 2.7 표이있습다가 있습니다.compact그리고.transform_values메서드, 해시에서 다음과 같은 작업을 수행할 수 있습니다.

class Hash 
  def deep_compact
    compact.transform_values{|vl| vl.is_a?(Hash) ? vl.deep_compact : vl }
  end
end

가장 깔끔한 구현이야, 임호.

  validated_params
    .to_h
    .delete_if {|_,v| !v.present? }

언급URL : https://stackoverflow.com/questions/3450641/removing-all-empty-elements-from-a-hash-yaml

반응형