Yuvalanmış bir Hash veya YAML dosyasındaki tüm boş öğeleri (boş liste öğeleri) kaldırmaya nasıl giderim?
Yuvalanmış bir Hash veya YAML dosyasındaki tüm boş öğeleri (boş liste öğeleri) kaldırmaya nasıl giderim?
Yanıtlar:
Hash'e böyle kompakt bir yöntem ekleyebilirsiniz.
class Hash
def compact
delete_if { |k, v| v.nil? }
end
end
veya özyinelemeyi destekleyen bir sürüm için
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
Hash#delete_if
yıkıcı bir işlemdir compact
. Kullanabilirsiniz Hash#reject
. Veya yöntemi çağırın Hash#compact!
.
compact
ve compact!
Ruby => 2.4.0 ve Rails => 4.1'de standart olarak gelir. Yine de özyinelemesizdir.
HashWithIndifferentAccess
.. stackoverflow.com/a/53958201/1519240
Rails 4.1 Hash # compact ve Hash # compact ekledi ! Ruby'nin Hash
sınıfının temel bir uzantısı olarak . Bunları şu şekilde kullanabilirsiniz:
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
# => {}
Dikkat: bu uygulama özyinelemeli değildir. Bir merak olarak, performans nedenleri #select
yerine bunu kullanarak uyguladılar #delete_if
. Kıyaslama için buraya bakın .
Rails 3 uygulamanıza backport yapmak istiyorsanız:
# 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 kullanın . Özel durumunuzda aşağıdakilere benzer:hsh.delete_if { |k, v| v.empty? }
proc = Proc.new { |k, v| v.kind_of?(Hash) ? (v.delete_if(&l); nil) : v.empty? }; hsh.delete_if(&proc)
NoMethodError
if atar v
.
Ruby 2.4+ kullanıyorsanız compact
vecompact!
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
Bu, boş karmaları da siler:
swoop = Proc.new { |k, v| v.delete_if(&swoop) if v.kind_of?(Hash); v.empty? }
hsh.delete_if &swoop
swoop = Proc.new { |k, v| v.delete_if(&swoop) if v.kind_of?(Hash); v.blank? }
Bir yakut karmasından boş anahtar / değer çiftlerini kaldırmak için Hash # reddetme özelliğini kullanabilirsiniz .
# 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"}
.empty?
Eğer kullanabilmesi için, sayılar için hata atar .blank?
içindeRails
hem karma hem de diziler için çalışır
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 biri cevap dayalı, bulamıyorum
kullanım - Helpers::RecursiveCompact.recursive_compact(something)
Bu iş parçacığının biraz eski olduğunu biliyorum ama Çok Boyutlu karmaları destekleyen daha iyi bir çözüm buldum. Delete_if kullanıyor mu? çok boyutlu hariç ve varsayılan olarak boş bir değere sahip her şeyi temizler ve bir blok geçirilirse, altlarından geçirilir.
# 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
Nil kayıtlarını (ve isteğe bağlı olarak boş kayıtları da) yinelemeli olarak filtreleyen bunun için bir deep_compact yöntemi yaptım:
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
Ruby'nin Hash#compact
, Hash#compact!
ve Hash#delete_if!
iç içe üzerinde çalışmaya yok nil
, empty?
ve / veya blank?
değerler. Son iki yöntem yıkıcı olduğu, ve bütün bu not nil
, ""
, false
, []
ve {}
değerleri olarak sayılırblank?
.
Hash#compact
ve Hash#compact!
yalnızca Rails veya Ruby 2.4.0 ve sonraki sürümlerinde kullanılabilir.
İşte nil
tüm false
değerleri tutarken tüm boş dizileri, karmaları, dizeleri ve değerleri kaldıran yıkıcı olmayan bir çözüm :
( gerektiğinde veya blank?
gerekirse değiştirilebilir .)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
Yıkıcı bir versiyon:
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
Veya, her iki sürümü de Hash
sınıfta örnek yöntemi olarak eklemek istiyorsanız :
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
Diğer seçenekler:
v.blank? && v != false
ile değiştirin v.nil? || v == ""
venil
değerleriv.blank? && v != false
ile değiştirinv.nil?
nil
false
Değerleri korumak ve diğer seçenekleri sunmak için 2017/03/15 DÜZENLENDİ
Hash içindeki null değerleri silmek için Simple one liner'da,
rec_hash.each {|key,value| rec_hash.delete(key) if value.blank? }
blank?
boş dizeleri de gider
Fasets kütüphanesi (standart kütüphaneden eksik özellikler) ile şu şekilde yapılabilir :
require 'hash/compact'
require 'enumerable/recursively'
hash.recursively { |v| v.compact! }
Numaralandırılabilir (Array, Hash dahil) ile çalışır.
Özyinelemeli yöntemin nasıl uygulandığına bakın.
Kendini tekrarlayan bir yöntem kullanmanın en iyisi olduğuna inanıyorum. Bu şekilde gerektiği kadar derine iner. Değer nil veya boş bir Karma ise, anahtar / değer çiftini silecektir.
class Hash
def compact
delete_if {|k,v| v.is_a?(Hash) ? v.compact.empty? : v.nil? }
end
end
Sonra onu kullanmak şöyle görünecektir:
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}}
Boş karmaları tutmak için bunu basitleştirebilirsiniz.
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
Nil'i kaldırmak için bunu deneyin
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}
hash.compact!
Https://stackoverflow.com/a/14773555/1519240 özyinelemeli sürümü çalışır, ancak HashWithIndifferentAccess
Hash türü olan sınıflarla birlikte çalışmaz .
İşte kullanıyorum sürüm:
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)
Karma gibi daha fazla sınıfı kabul eder.
Ayrıca değiştirebilir inject({})
tarafından inject(HashWithIndifferentAccess.new)
size sembolü ve dize ikisini de kullanarak yeni karma erişmek istiyorsanız.
İşte sahip olduğum bir şey:
# 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
Karmadan derin silme nil değerleri.
# 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
Eğer kullanıyorsanız Rails
(veya tek başına ActiveSupport
), sürümden başlayarak 6.1
, bir orada compact_blank
kaldırır yöntem blank
sağlamalarının değerleri.
Bu kullanan Object#blank?
bir öğe boşsa belirlenmesi için kaputun altında.
{ a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
# => { b: 1, f: true }
İşte dokümanlara bir bağlantı ve göreli PR'ye bir bağlantı .
Yıkıcı bir varyant da mevcuttur. Bkz Hash#compact_blank!
.
Yalnızca nil
değerleri kaldırmanız gerekiyorsa ,
lütfen Ruby yapı Hash#compact
ve Hash#compact!
yöntemlerini kullanmayı düşünün .
{ a: 1, b: false, c: nil }.compact
# => { a: 1, b: false }