Dada una matriz, un solo elemento o nulo, obtenga una matriz; los dos últimos son una matriz de un solo elemento y una matriz vacía, respectivamente.
Pensé erróneamente que Ruby funcionaría de esta manera:
[1,2,3].to_a #= [1,2,3] # Already an array, so no change
1.to_a #= [1] # Creates an array and adds element
nil.to_a #= [] # Creates empty array
Pero lo que realmente obtienes es:
[1,2,3].to_a #= [1,2,3] # Hooray
1.to_a #= NoMethodError # Do not want
nil.to_a #= [] # Hooray
Entonces, para resolver esto, necesito usar otro método, o podría programar un meta modificando el método to_a de todas las clases que pretendo usar, lo cual no es una opción para mí.
Entonces un método es:
result = nums.class == "Array".constantize ? nums : (nums.class == "NilClass".constantize ? [] : ([]<<nums))
El problema es que está un poco desordenado. ¿Existe una forma elegante de hacer esto? (Me sorprendería si esta es la forma Ruby-ish de resolver este problema)
¿Qué aplicaciones tiene esto? ¿Por qué incluso convertir a una matriz?
En ActiveRecord de Rails, llamar a say, user.posts
devolverá una matriz de publicaciones, una sola publicación o nil. Al escribir métodos que funcionan con los resultados de esto, es más fácil asumir que el método tomará una matriz, que puede tener cero, uno o muchos elementos. Método de ejemplo:
current_user.posts.inject(true) {|result, element| result and (element.some_boolean_condition)}
user.posts
nunca debe devolver una sola publicación. Al menos, nunca lo vi.==
lugar de=
, ¿verdad?[1,2,3].to_a
no no volver[[1,2,3]]
! Vuelve[1,2,3]
.Respuestas:
[*foo]
oArray(foo)
funcionará la mayor parte del tiempo, pero en algunos casos, como un hash, lo estropea.La única forma en que puedo pensar que funciona incluso para un hash es definir un método.
fuente
ensure_array
, extenderto_a
to_a
. Por ejemplo,{a: 1, b: 2}.each ...
funcionaría de manera diferente.Con ActiveSupport (rieles):
Array.wrap
Si no está utilizando Rails, puede definir su propio método similar al origen de Rails .
fuente
class Array; singleton_class.send(:alias_method, :hug, :wrap); end
para una ternura extra.La solución más sencilla es utilizar
[foo].flatten(1)
. A diferencia de otras soluciones propuestas, funcionará bien para matrices (anidadas), hashes ynil
:fuente
Kernel#Array
decir,Array()
es el más rápido de todos. Comparación de Ruby 2.5.1: Array (): 7936825.7 i / s. Array.wrap: 4199036.2 i / s - 1.89x más lento. wrap: 644030.4 i / s - 12.32x más lentoArray(whatever)
debería hacer el trucofuente
ActiveSupport (rieles)
ActiveSupport tiene un método bastante bueno para esto. Está cargado con Rails, por lo que definitivamente es la mejor manera de hacer esto:
Splat (Ruby 1.9+)
El operador de splat (
*
) desarma una matriz, si puede:Por supuesto, sin una matriz, hace cosas raras, y los objetos que "splat" deben colocarse en matrices. Es algo extraño, pero significa:
Si no tiene ActiveSupport, puede definir el método:
Aunque, si planea tener arreglos grandes y menos cosas que no sean arreglos, es posible que desee cambiarlo: el método anterior es lento con arreglos grandes e incluso puede hacer que su pila se desborde (Dios mío, meta). De todos modos, es posible que desee hacer esto en su lugar:
También tengo algunos puntos de referencia con y sin el operador teneray.
fuente
SystemStackError: stack level too deep
para 1M elementos (ruby 2.2.3).Hash#values_at
con 1 M de argumentos (usandosplat
) y arroja el mismo error.object.is_a? Array ? object : [*object]
?Array.wrap(nil)
[]
no devuelvenil
: /Qué tal si
fuente
[].push(anything).flatten(1)
¡trabajaría! ¡No aplana las matrices anidadas!Con el riesgo de decir lo obvio, y sabiendo que este no es el azúcar sintáctico más sabroso jamás visto en el planeta y áreas circundantes, este código parece hacer exactamente lo que usted describe:
fuente
puede sobrescribir el método de matriz de Object
todo hereda Object, por lo tanto to_a ahora se definirá para todo lo que hay bajo el sol
fuente
He revisado todas las respuestas y la mayoría no funciona en ruby 2+
Pero elado tiene la solución más elegante, es decir
Lamentablemente, esto tampoco funciona para ruby 2+ ya que obtendrá un error
Entonces, para arreglar eso, necesita requerir.
fuente
Dado que el método
#to_a
ya existe para las dos clases problemáticas principales (Nil
yHash
), simplemente defina un método para el resto extendiendoObject
:y luego puede llamar fácilmente a ese método en cualquier objeto:
fuente