bidimensionales arreglos ruby arrays

arreglos - Ruby: elegantemente convierte variable a una matriz si no ya una matriz



arreglos bidimensionales en ruby (10)

ActiveSupport (Rieles)

ActiveSupport tiene un método bastante agradable para esto. Está cargado con Rails, así que desafiantemente la mejor manera de hacerlo:

Array.wrap([1, 2, 3]) #=> [1, 2, 3] Array.wrap(nil) #=> nil

Splat (Ruby 1.9+)

El operador splat ( * ) desinstala una matriz, si puede:

*[1,2,3] #=> 1, 2, 3 (notice how this DOES not have braces)

Por supuesto, sin una matriz, hace cosas raras, y los objetos que "splat" deben colocarse en matrices. Es algo raro, pero significa:

[*[1,2,3]] #=> [1, 2, 3] [*5] #=> [5] [*nil] #=> [] [*{meh: "meh"}] #=> [[:meh, "meh"], [:meh2, "lol"]]

Si no tiene ActiveSupport, puede definir el método:

class Array def self.wrap(object) [*object] end end Array.wrap([1, 2, 3]) #=> [1, 2, 3] Array.wrap(nil) #=> nil

Aunque, si planeas tener matrices grandes y menos cosas que no sean de matriz, es posible que quieras cambiarlo; el método anterior es lento con matrices grandes e incluso puede hacer que tu pila se desborde (omg tan meta). De todos modos, es posible que desee hacer esto en su lugar:

class Array def self.wrap(object) object.is_a? Array ? object : [*object] end end Array.wrap([1, 2, 3]) #=> [1, 2, 3] Array.wrap(nil) #=> [nil]

También tengo algunos benchmarks con y sin el operador teneray.

Dada una matriz, un solo elemento, o nil, obtiene una matriz, siendo las dos últimas una matriz de un solo elemento y una matriz vacía, respectivamente.

Supuse 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, o necesito usar otro método, o podría metaprogramar 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 es un desastre. ¿Hay una manera elegante de hacer esto? (Me sorprendería si esta es la manera Ruby-ish para resolver este problema)

¿Qué aplicaciones tiene esto? ¿Por qué incluso convertir a una matriz?

En ActiveRecord de Rails, al llamar a decir, user.posts devolverá una matriz de publicaciones, una sola publicación o ninguna. Al escribir métodos que funcionan con los resultados de esto, es más fácil suponer 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)}


Como el método #to_a ya existe para las dos clases problemáticas principales ( Nil y Hash ), simplemente defina un método para el resto extendiendo Object :

class Object def to_a [self] end end

y luego puedes llamar fácilmente a ese método en cualquier objeto:

"Hello world".to_a # => ["Hello world"] 123.to_a # => [123] {a:1, b:2}.to_a # => [[:a, 1], [:b, 2]] nil.to_a # => []


Con ActiveSupport (Rails): Array.wrap

Array.wrap([1, 2, 3]) # => [1, 2, 3] Array.wrap(1) # => [1] Array.wrap(nil) # => [] Array.wrap({a: 1, b: 2}) # => [{:a=>1, :b=>2}]

Si no está utilizando Rails, puede definir su propio método similar a la fuente Rails .

class Array def self.wrap(object) if object.nil? [] elsif object.respond_to?(:to_ary) object.to_ary || [object] else [object] end end end


Con el riesgo de afirmar lo obvio, y sabiendo que este no es el azúcar sintáctico más sabroso jamás visto en el planeta y las áreas circundantes, este código parece hacer exactamente lo que usted describe:

foo = foo.is_a?(Array) ? foo : foo.nil? ? [] : [foo]


He revisado todas las respuestas y la mayoría de las veces no trabajo en ruby ​​2+

Pero elado tiene la solución más elegante es decir

Con ActiveSupport (Rails): Array.wrap

Array.wrap ([1, 2, 3]) # => [1, 2, 3]

Array.wrap (1) # => [1]

Array.wrap (nil) # => []

Array.wrap ({a: 1, b: 2}) # => [{: a => 1,: b => 2}]

Lamentablemente, esto tampoco funciona con ruby ​​2+ ya que obtendrás un error

undefined method `wrap'' for Array:Class

Entonces, para arreglar eso necesitas pedirlo.

requiere ''active_support / deprecation''

requiere ''active_support / core_ext / array / wrap''


La solución más simple es usar [foo].flatten(1) . A diferencia de otras soluciones propuestas, funcionará bien para matrices (anidadas), hash y nil :

def wrap(foo) [foo].flatten(1) end wrap([1,2,3]) #= [1,2,3] wrap([[1,2],[3,4]]) #= [[1,2],[3,4]] wrap(1) #= [1] wrap(nil) #= [nil] wrap({key: ''value''}) #= [{key: ''value''}]


Qué tal si

[].push(anything).flatten


puedes sobreescribir el método de matriz de Object

class Object def to_a [self] end end

todo hereda Objeto, por lo tanto, to_a ahora se definirá para todo lo que esté debajo del sol


Array(whatever) debería hacer el truco

Array([1,2,3]) # [1,2,3] Array(nil) # [] Array(1337) # [1337]


[*foo] o Array(foo) funcionarán la mayor parte del tiempo, pero en algunos casos como un hash, lo estropea.

Array([1, 2, 3]) # => [1, 2, 3] Array(1) # => [1] Array(nil) # => [] Array({a: 1, b: 2}) # => [[:a, 1], [:b, 2]] [*[1, 2, 3]] # => [1, 2, 3] [*1] # => [1] [*nil] # => [] [*{a: 1, b: 2}] # => [[:a, 1], [:b, 2]]

La única forma en que puedo pensar que funciona incluso para un hash es definir un método.

class Object; def ensure_array; [self] end end class Array; def ensure_array; to_a end end class NilClass; def ensure_array; to_a end end [1, 2, 3].ensure_array # => [1, 2, 3] 1.ensure_array # => [1] nil.ensure_array # => [] {a: 1, b: 2}.ensure_array # => [{a: 1, b: 2}]