2012-09-11 9 views
48

Necesito una forma de dividir una matriz en una serie de matrices dentro de otra matriz de igual tamaño. Alguien tiene algún método para hacer esto?División de una matriz en partes iguales en ruby ​​

Por ejemplo

a = [0, 1, 2, 3, 4, 5, 6, 7] 
a.method_i_need(3) 
a.inspect 
    => [[0,1,2], [3,4,5], [6,7]] 
+3

posible duplicado de [¿Cómo dividir (trozo) una matriz de rubíes en partes de los elementos de X?] (Http://stackoverflow.com/questions/2699584/how-to-split-chunk-a-ruby -array-into-parts-of-x-elements) –

+8

Desafortunadamente, el ejemplo elegido tiene el mismo resultado para "dividir en 3 grupos" y "dividir en grupos de 3 elementos", por eso tienes dos respuestas completamente diferentes. – tokland

Respuesta

102

estás buscando Enumerable#each_slice

a = [0, 1, 2, 3, 4, 5, 6, 7] 
a.each_slice(3) # => #<Enumerator: [0, 1, 2, 3, 4, 5, 6, 7]:each_slice(3)> 
a.each_slice(3).to_a # => [[0, 1, 2], [3, 4, 5], [6, 7]] 
+6

Es interesante cómo estas preguntas y respuestas básicas atraen la mayor cantidad de comentarios. –

+12

Solo una nota. Esto divide la matriz en grupos de tamaño 3. no en 3 grupos de igual tamaño. – yasith

+0

Si el tamaño de la matriz no se divide de manera uniforme en el número de sectores, ¿es posible fusionar la porción restante con la porción anterior? Dado su ejemplo, '[6, 7]' se combinaría con '[3, 4, 5]' para hacer '[3, 4, 5, 6, 7]'. – Mohamad

13

Trate

a.in_groups_of(3,false) 

Lo hará su trabajo

+12

Tenga en cuenta que ['in_groups_of'] (http://rails.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Array/Grouping.html) es específico de Rails (o más bien, ActiveSupport), mientras que la respuesta de @ Joshua se puede usar en Ruby en todos lados. Aún así, +1 para proporcionar una solución de trabajo. – Phrogz

+0

También está solo en [Array] (https://github.com/rails/rails/blob/ccf9577aee86ce1f766c5e8854e0c285dc38f8ac/activesupport/lib/active_support/core_ext/array/grouping.rb). –

+0

@Phrogz gracias por la información –

89

Tal vez estoy leyendo mal la questi ya que la otra respuesta ya está aceptada, pero sonaba como si quisieras dividir la matriz en 3 grupos iguales, independientemente del tamaño de cada grupo, en lugar de dividirla en N grupos de 3 como lo hacen las respuestas anteriores. Si eso es lo que está buscando, rieles (ActiveSupport) también tiene un método llamado in_groups:

a = [0,1,2,3,4,5,6] 
a.in_groups(2) # => [[0,1,2,3],[4,5,6,nil]] 
a.in_groups(3, false) # => [[0,1,2],[3,4], [5,6]] 

No creo que hay un rubí equivalente, sin embargo, se puede obtener aproximadamente los mismos resultados mediante la adición de este método sencillo:

class Array; def in_groups(num_groups) 
    return [] if num_groups == 0 
    slice_size = (self.size/Float(num_groups)).ceil 
    groups = self.each_slice(slice_size).to_a 
end; end 

a.in_groups(3) # => [[0,1,2], [3,4,5], [6]] 

la única diferencia (como se puede ver) es que esto no va a difundir el "espacio vacío" en todos los grupos; cada grupo, pero el último es igual en tamaño, y el último grupo siempre contiene el resto más todo el "espacio vacío".

Actualización: Como @rimsky astutamente señaló, el método anterior no siempre resultan en el número correcto de los grupos (a veces se crearán varias "grupos vacías" al final, y dejarlos fuera). Aquí hay una versión actualizada, reducida desde ActiveSupport's definition que extiende los extras para completar el número solicitado de grupos.

def in_groups(number) 
    group_size = size/number 
    leftovers = size % number 

    groups = [] 
    start = 0 
    number.times do |index| 
    length = group_size + (leftovers > 0 && leftovers > index ? 1 : 0) 
    groups << slice(start, length) 
    start += length 
    end 

    groups 
end 
+3

Sé que esta es una publicación anterior, pero para aquellos que están considerando el equivalente de ruby ​​anterior, no es del todo correcto. Si intenta dividir una matriz de 20 elementos en 11 grupos, terminará con solo 10 grupos. slice_size será 2 y 20 es divisible por 2. – rimsky

+0

Esto es lo que vine a buscar aquí. No para grupos de n tamaño, como la respuesta aceptada. Gracias. –

+0

Buena captura @rimsky! Actualizado;) – mltsy

0

Como escribió mltsy, in_groups(n, false) debe hacer el trabajo.

Solo quería agregar un pequeño truco para obtener el equilibrio correcto my_array.in_group(my_array.size.quo(max_size).ceil, false).

Aquí se muestra un ejemplo para ilustrar ese truco:

a = (0..8).to_a 
a.in_groups(4, false) => [[0, 1, 2], [3, 4], [5, 6], [7, 8]] 
a.in_groups(a.size.quo(4).ceil, false) => [[0, 1, 2], [3, 4, 5], [6, 7, 8]] 
1

Esto necesita un poco mejor inteligencia para manchar las piezas adicionales, pero es un comienzo razonable.

def i_need(bits, r) 
    c = r.count 
    (1..bits - 1).map { |i| r.shift((c + i) * 1.0/bits) } + [r] 
end 

> i_need(2, [1, 3, 5, 7, 2, 4, 6, 8]) 
=> [[1, 3, 5, 7], [2, 4, 6, 8]] 
> i_need(3, [1, 3, 5, 7, 2, 4, 6, 8]) 
=> [[1, 3, 5], [7, 2, 4], [6, 8]] 
> i_need(5, [1, 3, 5, 7, 2, 4, 6, 8]) 
=> [[1, 3], [5, 7], [2, 4], [6], [8]] 
Cuestiones relacionadas