ฉันจะลบองค์ประกอบว่างทั้งหมด (รายการว่าง) ออกจากไฟล์ Hash หรือ YAML ที่ซ้อนกันได้อย่างไร
ฉันจะลบองค์ประกอบว่างทั้งหมด (รายการว่าง) ออกจากไฟล์ Hash หรือ YAML ที่ซ้อนกันได้อย่างไร
คำตอบ:
คุณสามารถเพิ่มวิธีการที่กะทัดรัดให้กับ 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
Hash#delete_if
เป็นการดำเนินการทำลายล้างในขณะที่compact
วิธีการไม่ได้แก้ไขวัตถุ คุณสามารถใช้Hash#reject
. หรือโทรมาที่เมธอดHash#compact!
.
compact
และcompact!
มาตรฐานมาในรูบี => 2.4.0 และ Rails => 4.1 แม้ว่าจะไม่เกิดซ้ำ
HashWithIndifferentAccess
.. ตรวจสอบเวอร์ชันของฉันที่stackoverflow.com/a/53958201/1519240
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
# => {}
โปรดทราบ: การใช้งานนี้จะไม่เกิดซ้ำ ด้วยความอยากรู้อยากเห็นพวกเขาจึงนำมาใช้#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
proc = Proc.new { |k, v| v.kind_of?(Hash) ? (v.delete_if(&l); nil) : v.empty? }; hsh.delete_if(&proc)
NoMethodError
if v
เป็นศูนย์
หากคุณใช้ 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
swoop = Proc.new { |k, v| v.delete_if(&swoop) if v.kind_of?(Hash); v.blank? }
คุณสามารถใช้Hash # ปฏิเสธเพื่อลบคู่คีย์ / ค่าที่ว่างเปล่าออกจาก Ruby Hash
# 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?
ข้อผิดพลาดสำหรับตัวเลขเพื่อให้คุณสามารถใช้.blank?
ในRails
ใช้ได้กับทั้งแฮชและอาร์เรย์
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/15 เพื่อรักษาfalse
ค่าและนำเสนอตัวเลือกอื่น ๆ
เวอร์ชันของเรา: มันยังล้างสตริงว่างและค่าศูนย์
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
ใน Simple one liner สำหรับการลบค่า null ใน Hash
rec_hash.each {|key,value| rec_hash.delete(key) if value.blank? }
blank?
สำหรับสายที่ว่างเปล่าเช่นกัน
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)
จะรับคลาสอื่น ๆ ที่เหมือน Hash
คุณยังสามารถแทนที่inject({})
ด้วยinject(HashWithIndifferentAccess.new)
ถ้าคุณต้องการเข้าถึงแฮชใหม่โดยใช้ทั้งสัญลักษณ์และสตริง
หากคุณใช้Rails
(หรือแบบสแตนด์อโลนActiveSupport
) โดยเริ่มจากเวอร์ชัน6.1
จะมีcompact_blank
วิธีการลบblank
ค่าออกจากแฮช
ใช้Object#blank?
ใต้ฝากระโปรงเพื่อพิจารณาว่ารายการว่างหรือไม่
{ a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
# => { b: 1, f: true }
นี่คือเชื่อมโยงไปยังเอกสารและเชื่อมโยงไปยังญาติประชาสัมพันธ์
นอกจากนี้ยังมีรูปแบบการทำลายล้าง ดูHash#compact_blank!
.
หากคุณต้องการลบเฉพาะnil
ค่า
โปรดพิจารณาใช้ Ruby build-in Hash#compact
และHash#compact!
method
{ a: 1, b: false, c: nil }.compact
# => { a: 1, b: false }
ฉันเชื่อว่าควรใช้วิธีการเรียกซ้ำด้วยตนเอง วิธีนั้นจะลึกเท่าที่จำเป็น การดำเนินการนี้จะลบคู่ค่าคีย์หากค่าเป็นศูนย์หรือ Hash ว่างเปล่า
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
ลองสิ่งนี้เพื่อลบศูนย์
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!
นี่คือสิ่งที่ฉันมี:
# 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
ค่าศูนย์การลบลึกจากแฮช
# 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