2012-09-11 8 views
48

Ho bisogno di un modo per dividere un array in un gruppo di matrici all'interno di un altro array di dimensioni uguali. Qualcuno ha qualche metodo per farlo?Divisione di un array in parti uguali in rubino

Per esempio

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

possibile duplicato di [Come dividere (pezzo) una matrice di Ruby in parti di elementi di X?] (Http://stackoverflow.com/questions/2699584/how-to-split-chunk-a-ruby -array-in-parts-of-x-elements) –

+8

È spiacevole che l'esempio scelto abbia lo stesso risultato per "dividere in 3 gruppi" e "dividere in gruppi di 3 elementi", ecco perché hai ottenuto due risposte completamente diverse. – tokland

risposta

102

siete alla ricerca di 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

È interessante notare come queste domande e risposte di base attirino il maggior numero di buzz. –

+12

Solo una nota. Questo divide l'array in gruppi di dimensioni 3. non in 3 gruppi di dimensioni uguali. – yasith

+0

Se la dimensione della matrice non si divide uniformemente nel numero di sezioni, è possibile unire la parte rimanente con la sezione precedente? Dato il tuo esempio, '[6, 7]' verrebbe unito a '[3, 4, 5]' per rendere '[3, 4, 5, 6, 7]'. – Mohamad

13

Prova

a.in_groups_of(3,false) 

Si farà il vostro lavoro

+12

Nota che ['in_groups_of'] (http://rails.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Array/Grouping.html) è specifico di Rails (o piuttosto di ActiveSupport), mentre la risposta di @ Joshua è utilizzabile in Ruby ovunque. Ancora, +1 per fornire una soluzione di lavoro. – Phrogz

+0

È anche solo su [Array] (https://github.com/rails/rails/blob/ccf9577aee86ce1f766c5e8854e0c285dc38f8ac/activesupport/lib/active_support/core_ext/array/grouping.rb). –

+0

@Phrogz grazie per le informazioni –

89

Forse sto fraintendendo il QUESTI da quando l'altra risposta è già accettata, ma sembrava che tu volessi dividere l'array in 3 gruppi uguali, indipendentemente dalla dimensione di ogni gruppo, piuttosto che dividerlo in N gruppi di 3 come fanno le risposte precedenti. Se questo è quello che stai cercando, Rails (ActiveSupport) ha anche un metodo chiamato 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]] 

Io non credo che ci sia un rubino equivalente, tuttavia, è possibile ottenere circa gli stessi risultati con l'aggiunta di questo metodo semplice:

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]] 

l'unica differenza (come potete vedere) è che questo non si diffonderà lo "spazio vuoto", in tutti i gruppi; ogni gruppo, ma l'ultimo è di dimensioni uguali, e l'ultimo gruppo contiene sempre il resto più tutto lo "spazio vuoto".

Aggiornamento: Come @rimsky acutamente indicate, il metodo di cui sopra non comporta sempre il numero corretto di gruppi (talvolta creerà più "gruppi vuoti" alla fine, e lasciare fuori). Ecco una versione aggiornata, ridotta da ActiveSupport's definition che espande gli extra per riempire il numero richiesto di gruppi.

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

So che questo è un vecchio post, ma per coloro che stanno considerando l'equivalente rubino sopra, non è del tutto corretto. Se provi a dividere un array di 20 elementi in 11 gruppi, finirai con solo 10 gruppi. slice_size sarà 2 e 20 è divisibile per 2. – rimsky

+0

Questo è quello che sono venuto qui cercando. Non per gruppi di n dimensioni, come la risposta accettata. Grazie. –

+0

Nice catch @rimsky! Aggiornato;) – mltsy

0

Come ha scritto mltsy, in_groups(n, false) dovrebbe fare il lavoro.

Volevo solo aggiungere un piccolo trucco per ottenere il giusto equilibrio my_array.in_group(my_array.size.quo(max_size).ceil, false).

Ecco un esempio per illustrare quel trucco:

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

questo ha bisogno un po 'di più intelligenza per spalmare i pezzi in più, ma è un inizio ragionevole.

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]] 
Problemi correlati