arreglos - array ruby
¿Cómo se agrega una matriz a otra matriz en Ruby y no se obtiene un resultado multidimensional? (14)
¡Puedes usar el operador +
!
irb(main):001:0> a = [1,2]
=> [1, 2]
irb(main):002:0> b = [3,4]
=> [3, 4]
irb(main):003:0> a + b
=> [1, 2, 3, 4]
Puede leer todo sobre la clase de matriz aquí: http://ruby-doc.org/core/classes/Array.html
somearray = ["some", "thing"]
anotherarray = ["another", "thing"]
somearray.push(anotherarray.flatten!)
Esperaba
["some","thing","another","thing"]
Al elaborar la respuesta de @Pilcrow, la única respuesta adecuada para matrices grandes es concat
( +
), ya que es rápida y no asigna un nuevo objeto para ser recolectado cuando se opera dentro de un bucle.
Aquí está el punto de referencia:
require ''benchmark''
huge_ary_1 = Array.new(1_000_000) { rand(5_000_000..30_000_00) }
huge_ary_2 = Array.new(1_000_000) { rand(35_000_000..55_000_00) }
Benchmark.bm do |bm|
p ''-------------------CONCAT ----------------''
bm.report { huge_ary_1.concat(huge_ary_2) }
p ''------------------- PUSH ----------------''
bm.report { huge_ary_1.push(*huge_ary_2) }
end
Resultados:
user system total real
"-------------------CONCAT ----------------"
0.000000 0.000000 0.000000 ( 0.009388)
"------------------- PUSH ----------------"
example/array_concat_vs_push.rb:13:in `block (2 levels) in <main>'': stack level too deep (SystemStackError)
Como puede ver, al usar push
lanza un ERROR : stack level too deep (SystemStackError)
cuando los arreglos son lo suficientemente grandes.
Aquí hay dos formas, observe en este caso que la primera forma devuelve una nueva matriz (se traduce a somearray = somearray + anotherarray)
somearray = ["some", "thing"]
anotherarray = ["another", "thing"]
somearray += anotherarray # => ["some", "thing", "another", "thing"]
somearray = ["some", "thing"]
somearray.concat anotherarray # => ["some", "thing", "another", "thing"]
El enfoque más limpio es usar el método Array # concat ; no creará una nueva matriz (a diferencia de la Matriz # + que hará lo mismo pero creará una nueva matriz).
Directamente de los documentos ( http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-concat ):
concat (other_ary)
Anexa los elementos de other_ary a self.
Asi que
[1,2].concat([3,4]) #=> [1,2,3,4]
Array # concat no aplanará una matriz multidimensional si se pasa como argumento. Tendrá que manejarlo por separado:
arr= [3,[4,5]]
arr= arr.flatten #=> [3,4,5]
[1,2].concat(arr) #=> [1,2,3,4,5]
Por último, puede usar nuestra gema de corelib ( https://github.com/corlewsolutions/corelib ) que agrega ayudantes útiles a las clases principales de Ruby. En particular, tenemos un método Array # add_all que aplanará automáticamente las matrices multidimensionales antes de ejecutar el Concat.
Intenta esto, combinará tus arreglos eliminando duplicados.
array1 = ["foo", "bar"]
array2 = ["foo1", "bar1"]
array3 = array1|array2
http://www.ruby-doc.org/core/classes/Array.html
Más documentación ver en "Set Union"
La pregunta, esencialmente, es "cómo concatenar matrices en Ruby". Naturalmente, la respuesta es usar concat
o +
como se menciona en casi todas las respuestas.
Una extensión natural de la pregunta sería "cómo realizar la concatenación por filas de arreglos 2D en Ruby". Cuando busqué en Google "matrices de rubí concatenadas", esta pregunta de SO fue el principal resultado, así que pensé que dejaría mi respuesta a esa pregunta (no formulada pero relacionada) aquí para la posteridad.
En algunas aplicaciones es posible que desee "concatenar" dos matrices 2D en forma de fila. Algo como,
[[a, b], | [[x], [[a, b, x],
[c, d]] | [y]] => [c, d, y]]
Esto es algo así como "aumentar" una matriz. Por ejemplo, utilicé esta técnica para crear una única matriz de adyacencia para representar un gráfico de un grupo de matrices más pequeñas. Sin esta técnica, habría tenido que recorrer los componentes de una manera que podría haber sido propenso a los errores o frustrante de pensar. Podría haber tenido que hacer un each_with_index
, por ejemplo. En cambio, combiné zip y flatten siguiente manera,
# given two multi-dimensional arrays that you want to concatenate row-wise
m1 = [[:a, :b], [:c, :d]]
m2 = [[:x], [:y]]
m1m2 = m1.zip(m2).map(&:flatten)
# => [[:a, :b, :x], [:c, :d, :y]]
Método sencillo que funciona con la versión Ruby> = 2.0 pero no con versiones anteriores:
irb(main):001:0> a=[1,2]
=> [1, 2]
irb(main):003:0> b=[3,4]
=> [3, 4]
irb(main):002:0> c=[5,6]
=> [5, 6]
irb(main):004:0> [*a,*b,*c]
=> [1, 2, 3, 4, 5, 6]
Me resulta más fácil empujar o agregar matrices y luego aplanarlas en su lugar, así:
somearray = ["some", "thing"]
anotherarray = ["another", "thing"]
somearray.push anotherarray # => ["some", "thing", ["another", "thing"]]
#or
somearray << anotherarray # => ["some", "thing", ["another", "thing"]]
somearray.flatten! # => ["some", "thing", "another", "thing"]
somearray # => ["some", "thing", "another", "thing"]
Me sorprende que nadie haya mencionado reduce
, lo que funciona bien cuando tienes una serie de matrices:
lists = [["a", "b"], ["c", "d"]]
flatlist = lists.reduce(:+) # ["a", "b", "c", "d"]
Si los nuevos datos pueden ser una matriz o un escalar, y desea evitar que los nuevos datos se aniden si se tratara de una matriz, ¡el operador splat es increíble! Devuelve un escalar para un escalar y una lista desempaquetada de argumentos para una matriz.
1.9.3-p551 :020 > a = [1, 2]
=> [1, 2]
1.9.3-p551 :021 > b = [3, 4]
=> [3, 4]
1.9.3-p551 :022 > c = 5
=> 5
1.9.3-p551 :023 > a.object_id
=> 6617020
1.9.3-p551 :024 > a.push *b
=> [1, 2, 3, 4]
1.9.3-p551 :025 > a.object_id
=> 6617020
1.9.3-p551 :026 > a.push *c
=> [1, 2, 3, 4, 5]
1.9.3-p551 :027 > a.object_id
=> 6617020
Solo otra forma de hacerlo.
[somearray, anotherarray].flatten
=> ["some", "thing", "another", "thing"]
Tienes una idea viable, pero el #flatten!
está en el lugar equivocado: aplana su receptor, por lo que puede usarlo para convertir [1, 2, [''foo'', ''bar'']]
en [1,2,''foo'',''bar'']
.
Sin duda estoy olvidando algunos enfoques, pero puedes concatenar :
a1.concat a2
a1 + a2 # creates a new array, as does a1 += a2
o añadir / añadir
a1.push(*a2) # note the asterisk
a2.unshift(*a1) # note the asterisk, and that a2 is the receiver
o empalme
a1[a1.length, 0] = a2
a1[a1.length..0] = a2
a1.insert(a1.length, *a2)
o añadir y aplanar :
(a1 << a2).flatten! # a call to #flatten instead would return a new array
(array1 + array2).uniq
De esta manera obtienes primero los elementos de array1. No obtendrá duplicados.
["some", "thing"] + ["another" + "thing"]