2012-02-23 12 views
6

Tengo una matriz y quiero insertar un nuevo elemento entre todos los elementos, de alguna manera como el método join. Por ejemplo, tengo¿Cómo insertar un nuevo elemento entre todos los elementos de una matriz de Ruby?

[1, [], "333"] 

y lo que necesito es

[1, {}, [], {}, "333"] 

Nota se insertó un nuevo hash de vacío entre todos los elementos.

Editar: Actualmente lo que tengo es:

irb(main):028:0> a = [1, [], "333"] 
=> [1, [], "333"] 
irb(main):029:0> a = a.inject([]){|x, y| x << y; x << {}; x} 
=> [1, {}, [], {}, "333", {}] 
irb(main):030:0> a.pop 
=> {} 
irb(main):031:0> a 
=> [1, {}, [], {}, "333"] 
irb(main):032:0> 

Quiero saber la mejor manera.

+0

'x.push (y, {})' es más corto, tanto '<<' como 'push' return array, por lo que no necesita'; x', 'inject' es lento –

Respuesta

14
[1, 2, 3].flat_map { |x| [x, :a] }[0...-1] 
#=> [1, :a, 2, :a, 3] 

FYI, que la función se llama intersperse (al menos en Haskell).

[Actualización] Si se quiere evitar el corte (que creó una copia de la matriz):

[1, 2, 3].flat_map { |x| [x, :a] }.tap(&:pop) 
#=> [1, :a, 2, :a, 3] 
+0

No haría '[0 ..- 1]' en Haskell (y probablemente también en Ruby) –

+0

@VictorMoroz, ¿qué harías? –

+0

@VictorMoroz: se agregó un fragmento en el lugar. Ruby no tiene abstracción para esto, así que he usado tap + pop. – tokland

1
a = [1,2,3] 
h, *t = a 
r = [h] 
t.each do |e| 
    r.push({}, e) 
end 
r #=> [1, {}, 2, {}, 3] 
1

Se podría hacer algo como:

a = [1, [], "333"] 
new_a = a.collect {|e| [e, {}]}.flatten(1) 
=> [1, {}, [], {}, "333", {}] 

Es necesario hacer .flatten(1) porque va a aplanar su matriz en blanco sin ella.

O como dice @David Grayson en el comentario, puede hacer un flat_map que hará lo mismo.

a.flat_map {|e| [e, {}]} 
=> [1, {}, [], {}, "333", {}] 

@tokland tiene la respuesta correcta si el último {} no es necesario. Devuelve un segmento de 0 a longitud - 1 o [0..-1].

+1

Versión más corta:' a.flat_map {| e | [e, {}]} ' –

+0

¡Oh, bien! Y no aplana la matriz en blanco. Buena llamada. –

+1

solo el último '{}' no fue requerido –

0
irb(main):054:0* [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(1).flat_map {|e| e << "XXX"}[0...-1] 
=> [1, "XXX", 2, "XXX", 3, "XXX", 4, "XXX", 5, "XXX", 6, "XXX", 7, "XXX", 8, "XXX", 9] 
irb(main):055:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(2).flat_map {|e| e << "XXX"}[0...-1] 
=> [1, 2, "XXX", 3, 4, "XXX", 5, 6, "XXX", 7, 8, "XXX", 9] 
irb(main):056:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(3).flat_map {|e| e << "XXX"}[0...-1] 
=> [1, 2, 3, "XXX", 4, 5, 6, "XXX", 7, 8, 9] 
irb(main):057:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(4).flat_map {|e| e << "XXX"}[0...-1] 
=> [1, 2, 3, 4, "XXX", 5, 6, 7, 8, "XXX", 9] 
irb(main):058:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(5).flat_map {|e| e << "XXX"}[0...-1] 
=> [1, 2, 3, 4, 5, "XXX", 6, 7, 8, 9] 
irb(main):059:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(6).flat_map {|e| e << "XXX"}[0...-1] 
=> [1, 2, 3, 4, 5, 6, "XXX", 7, 8, 9] 
irb(main):060:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(7).flat_map {|e| e << "XXX"}[0...-1] 
=> [1, 2, 3, 4, 5, 6, 7, "XXX", 8, 9] 
irb(main):061:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(8).flat_map {|e| e << "XXX"}[0...-1] 
=> [1, 2, 3, 4, 5, 6, 7, 8, "XXX", 9] 
irb(main):062:0> [1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(9).flat_map {|e| e << "XXX"}[0...-1] 
=> [1, 2, 3, 4, 5, 6, 7, 8, 9] 
irb(main):063:0> 
0

Otro que es similar a Tokland de:

xs.inject([]){|x,y| x << y << {}}[0...-1] 
1

Otra similares la solución usa #product:

[1, 2, 3].product([{}]).flatten(1)[0...-1] 
# => [ 1, {}, 2, {}, 3 ] 
0

Un enfoque consiste en comprimir otra serie de elementos deseados y luego se aplanan con depth = 1:

> arr = [1, [], "333"] 
> element = {} 
> interspersed = arr.zip([element] * (arr.size - 1)).flatten(1).compact 
> # [1, {}, [], {}, "333" ] 

Puede extender Array para que este comportamiento sea más accesible.

class Array 
    def intersperse(elem) 
    self.zip([elem] * (self.size - 1)).flatten(1).compact 
    end 
end 

por ejemplo,

[43] de palanca (principal)> [1,2,3].intercalar ('a')
=> [1, "a", 2 "a", 3]

0
[1, 2, 3, 4, 5].inject { |memo, el| Array(memo) << {} << el } 
#=> [1, {}, 2, {}, 3, {}, 4, {}, 5] 

inject utilizará el primer elemento para empezar, por lo que no es necesario para meterse con los índices.

Cuestiones relacionadas