Bagaimana cara saya menghapus semua elemen kosong (daftar kosong item) dari file Hash atau YAML bersarang?
Bagaimana cara saya menghapus semua elemen kosong (daftar kosong item) dari file Hash atau YAML bersarang?
Jawaban:
Anda bisa menambahkan metode ringkas ke Hash seperti ini
class Hash
def compact
delete_if { |k, v| v.nil? }
end
end
atau untuk versi yang mendukung rekursi
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
adalah operasi yang merusak, sementara compact
metode tidak mengubah objek. Anda bisa menggunakannya Hash#reject
. Atau hubungi metode Hash#compact!
.
compact
dan compact!
datang standar di Ruby => 2.4.0, dan Rails => 4.1. Mereka non-rekursif.
HashWithIndifferentAccess
.. Periksa versi saya di stackoverflow.com/a/53958201/1519240
Rails 4.1 menambahkan Hash # compact dan Hash # compact! sebagai ekstensi inti ke Hash
kelas Ruby . Anda dapat menggunakannya seperti ini:
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
# => {}
Kepala: implementasi ini tidak rekursif. Sebagai rasa ingin tahu, mereka mengimplementasikannya menggunakan #select
bukan #delete_if
karena alasan kinerja. Lihat di sini untuk patokan .
Jika Anda ingin membuat backport ke aplikasi Rails 3 Anda:
# 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
Gunakan hsh.delete_if . Dalam kasus spesifik Anda, sesuatu seperti: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 v
is nil.
Jika Anda menggunakan Ruby 2.4+, Anda dapat menelepon compact
dancompact!
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
Yang ini juga akan menghapus hash yang kosong:
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? }
Anda dapat menggunakan Hash # reject untuk menghapus pasangan kunci / nilai kosong dari Hash ruby.
# 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?
melempar kesalahan untuk angka-angka, sehingga Anda dapat menggunakan .blank?
inRails
bekerja untuk hash dan array
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 berdasarkan jawaban someones, cant find
penggunaan - Helpers::RecursiveCompact.recursive_compact(something)
Saya tahu utas ini agak lama tetapi saya datang dengan solusi yang lebih baik yang mendukung hash Multidimensi. Ini menggunakan delete_if? kecuali multidimensi dan membersihkan apa pun dengan nilai kosong secara default dan jika blok dilewatkan maka akan diturunkan melalui anak-anak itu.
# 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
Saya membuat metode deep_compact untuk ini yang secara rekursif menyaring catatan nil (dan juga catatan kosong):
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 Hash#compact
, Hash#compact!
dan Hash#delete_if!
tidak bekerja pada nested nil
, empty?
dan / atau blank?
nilai - nilai. Perhatikan bahwa dua yang terakhir metode yang merusak, dan bahwa semua nil
, ""
, false
, []
dan {}
nilai-nilai dihitung sebagai blank?
.
Hash#compact
dan Hash#compact!
hanya tersedia di Rails, atau Ruby versi 2.4.0 ke atas.
Berikut adalah solusi non-destruktif yang menghapus semua array kosong, hash, string, dan nil
nilai, sembari menjaga semua false
nilai:
( blank?
dapat diganti dengan nil?
atau empty?
sesuai kebutuhan.)
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
Versi destruktif:
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
Atau, jika Anda ingin menambahkan kedua versi sebagai metode instan di Hash
kelas:
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
Pilihan lain:
v.blank? && v != false
dengan v.nil? || v == ""
untuk menghapus string dan nil
nilai kosongv.blank? && v != false
dengan v.nil?
untuk menghapus nil
nilai-nilai secara ketatEDITED 2017/03/15 untuk menjaga false
nilai dan menyajikan opsi lain
Dalam Simple one liner untuk menghapus nilai null di Hash,
rec_hash.each {|key,value| rec_hash.delete(key) if value.blank? }
blank?
berlaku untuk string kosong juga
Dapat dilakukan dengan facet library (fitur yang hilang dari perpustakaan standar), seperti itu:
require 'hash/compact'
require 'enumerable/recursively'
hash.recursively { |v| v.compact! }
Bekerja dengan Enumerable apa pun (termasuk Array, Hash).
Lihat bagaimana metode rekursif diimplementasikan.
Saya percaya akan lebih baik menggunakan metode rekursif diri. Dengan begitu ia berjalan sedalam yang dibutuhkan. Ini akan menghapus pasangan nilai kunci jika nilainya nol atau Hash kosong.
class Hash
def compact
delete_if {|k,v| v.is_a?(Hash) ? v.compact.empty? : v.nil? }
end
end
Kemudian menggunakannya akan terlihat seperti ini:
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}}
Untuk menyimpan hash kosong, Anda dapat menyederhanakan ini.
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
Coba ini untuk menghapus nol
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!
Versi rekursif https://stackoverflow.com/a/14773555/1519240 berfungsi, tetapi tidak dengan HashWithIndifferentAccess
atau kelas lain yang merupakan jenis Hash ..
Ini adalah versi yang saya gunakan:
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)
akan menerima lebih banyak kelas yang seperti Hash.
Anda juga dapat mengganti inject({})
dengan inject(HashWithIndifferentAccess.new)
jika Anda ingin mengakses hash baru menggunakan simbol dan string.
Ini adalah sesuatu yang saya miliki:
# 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
Nilai nih penghapusan dalam dari hash.
# 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
Jika Anda menggunakan Rails
(atau mandiri ActiveSupport
), mulai dari versi 6.1
, ada compact_blank
metode yang menghapus blank
nilai dari hash.
Ini digunakan di Object#blank?
bawah tenda untuk menentukan apakah suatu barang kosong.
{ a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
# => { b: 1, f: true }
Berikut adalah tautan ke dokumen dan tautan ke PR relatif .
Varian destruktif juga tersedia. Lihat Hash#compact_blank!
.
Jika Anda hanya perlu menghapus nil
nilai,
tolong, pertimbangkan untuk menggunakan Ruby build-in Hash#compact
dan Hash#compact!
metode.
{ a: 1, b: false, c: nil }.compact
# => { a: 1, b: false }