¿Qué debo hacer para eliminar todos los elementos vacíos (elementos de la lista vacía) de un archivo Hash o YAML anidado?¿Eliminar todos los elementos vacíos de un hash/YAML?
Respuesta
Se podría añadir un método compacto en Hash como esto
class Hash
def compact
delete_if { |k, v| v.nil? }
end
end
o para una versión que soporta la recursividad
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
Use hsh.delete_if. En su caso específico, algo así como: hsh.delete_if { |k, v| v.empty? }
recursiva uno: 'proc = Proc.new {| k, v | v.kind_of? (Hash)? (v.delete_if (&l); nil): v.empty?}; hsh.delete_if (& proc) ' –
Creo que hay un error ortográfico en su respuesta correcta: proc = Proc.new {| k, v | v.kind_of? (Hash)? (V.delete_if (&proc); nil): v.empty?}; Hsh.delete_if (& proc) – acw
Sería genial si se añadiera #compact a Hash. –
Éste sería eliminar los hashes vacías también:
swoop = Proc.new { |k, v| v.delete_if(&swoop) if v.kind_of?(Hash); v.empty? }
hsh.delete_if &swoop
versión de rieles, que también funciona con valores de otros tipos distintos de Array, Hash o String (como Fixnum): 'swoop = Proc.new {| k, v | v.delete_if (& swoop) si v.kind_of? (Hash); v.blank? } ' – wdspkr
Sé que este hilo es un poco viejo, pero se me ocurrió una mejor solución que soporta los hashes multidimensionales. Utiliza delete_if? excepto que es multidimensional y borra todo lo que tiene un valor vacío por defecto y si se pasa un bloque se pasa a través de sus hijos.
# 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
nuestra versión: también limpia las cadenas vacías y nulas valores
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
Rails 4.1 agregó Hash#compact y Hash#compact! como extensiones principales a la clase Hash
de Ruby. Puede usarlos así:
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 up: esta implementación no es recursiva. Como curiosidad, lo implementaron usando #select
en lugar de #delete_if
por razones de rendimiento. Ver here for the benchmark.
En caso de que acondicionarlo a sus carriles 3 aplicación:
# 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
Agradable y ordenado, pero probablemente valga la pena señalar que, a diferencia de la respuesta aceptada, la extensión Rails no es recursiva. – SirRawlins
En Simple de un forro para borrar los valores nulos en Hash,
rec_hash.each {|key,value| rec_hash.delete(key) if value.blank? }
cuidado, 'en blanco?' Vale para cadenas vacías también –
Creo que sería mejor usar un método auto recursivo De esa forma va tan profundo como se necesita. Esto eliminará el par de valores clave si el valor es nulo o un Hash vacío.
class Hash
def compact
delete_if {|k,v| v.is_a?(Hash) ? v.compact.empty? : v.nil? }
end
end
Luego, utilizando va a tener este aspecto:
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}}
Para mantener los hashes vacíos podrá simplificar esto.
class Hash
def compact
delete_if {|k,v| v.compact if v.is_a?(Hash); v.nil? }
end
end
hmm. referencias circulares podrían conducir a un bucle infinito IIUC. –
Hice un método deep_compact para este que filtra recursivamente a cabo nil registros (y opcionalmente, registros en blanco también):
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
Puede utilizar Hash#reject eliminar los pares clave/valor vacías de una 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"}
FYI: '.empty?' Arroja un error para los números, por lo que puede usar '.blank?' En 'Rails' – illusionist
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
se podría hacer con facets biblioteca (una serie de características que faltan de la biblioteca estándar), así:
require 'hash/compact'
require 'enumerable/recursively'
hash.recursively { |v| v.compact! }
funciona con cualquier Enumerable (incluyendo Array, Hash).
Mire cómo se implementa recursively method.
de Hash#compact
, Hash#compact!
y Hash#delete_if!
Rubí no funcionan en anidada nil
, empty?
y/o blank?
valores. Tenga en cuenta que los dos últimos métodos son destructivos, y que todos los valores nil
, ""
, false
, []
y {}
se cuentan como blank?
.
Hash#compact
y Hash#compact!
solo están disponibles en Rails o Ruby versión 2.4.0 y superior.
Aquí es una solución no destructiva que elimina todas las matrices vacías, hashes, cuerdas y nil
valores, manteniendo todas las false
valores: (. blank?
se pueden sustituir por nil?
o empty?
según sea necesario)
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
Una versión destructiva:
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
O bien, si desea agregar las dos versiones como métodos de instancia de la clase 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
Otras opciones:
- Reemplazar
v.blank? && v != false
conv.nil? || v == ""
para eliminar estrictamente cadenas vacías ynil
valores - Reemplazar
v.blank? && v != false
conv.nil?
para eliminar estrictamentenil
valores - Etc.
EDITADO 15/03/2017 mantener false
valores y presentes otras opciones
probar este para eliminar nula
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}
- 1. Cómo eliminar todos los XElements vacíos
- 2. Eliminar todos los elementos dentro de linearlayout
- 3. ¿Cómo eliminar todos los elementos de ListBox?
- 4. Eliminar todos los elementos de una lista
- 5. Scala ArrayBuffer eliminar todos los elementos con un prédicat
- 6. C# - Lista - eliminar todos los elementos pero NO los primeros
- 7. Eliminando todos los búferes vacíos en VIM
- 8. Cómo eliminar todos los elementos de SQLite en Android
- 9. Cómo eliminar la lista vista de todos los elementos
- 10. HTML5 elementos vacíos
- 11. Rails 3 eliminar todos los elementos de una matriz
- 12. cómo eliminar todos los elementos en una tabla de Lua?
- 13. Eliminar todos los elementos después de cierto elemento
- 14. ¿Cómo elimino los elementos vacíos del dominio usando jQuery?
- 15. Eliminar todos los niños en DOM elementos div
- 16. Deserializar Xml con elementos vacíos en C#
- 17. ¿Cómo eliminar todos los elementos en String array en java?
- 18. Eliminar una clase para todos los elementos secundarios
- 19. Obtener todos los elementos de un ArrayAdapter
- 20. Extracción de elementos vacíos de un vector de cadenas
- 21. Obtener todos los elementos de opciones seleccionados de todos los elementos seleccionados en un formulario
- 22. Comprobando si todos los elementos de la matriz están vacíos PHP
- 23. eliminación de elementos vacíos finales en Python
- 24. ¿Cómo verificar si los elementos del formulario no están vacíos?
- 25. Eliminar todos los atributos
- 26. Ordenando todos los elementos en un XDocument
- 27. jaxb marshalling omitir elementos vacíos
- 28. Retire todos los elementos secundarios de un StackPanel
- 29. ¿Cómo puedo eliminar todos los valores vacíos cuando exploto una cadena usando PHP?
- 30. Eliminar párrafos "vacíos" con jQuery
compact solo debe eliminar nils. No falsy valores –
un muy buen punto! Actualicé solo valores compactos nulos. – opsb
Esto tiene un problema: 'Hash # delete_if' es una operación destructiva, mientras que los métodos' compact' no modifican el objeto. Puede usar 'Hash # reject'. O llame al método 'Hash # compact!'. – tokland