Palavras-chave: Ruby, array, divide
Suponha que você tenha um array de X elementos e precise dividi-lo em arrays com Y elementos cada. A flexibilidade de Ruby nos permite definir operadores novos para as classes, então vamos criar um operador de dividir (/) para a classe Array:
class Array def / len inject([]) do |ary, x| ary << [] if [*ary.last].nitems % len == 0 ary.last << x ary end end end
Vamos rodar agora com alguns arrays para ver o que aconteceu:
p (1..10).to_a / 2 => [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]] p %w(hiro ando nikki jessica sylar) / 2 => [["hiro", "ando"], ["nikki", "jessica"], ["sylar"]] p (1..10).to_a / 4 => [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
Vamos analisar cada caso:
- Aqui temos um array de 10 elementos e dividimos por 2, retornando vários arrays com 2 elementos.
- Aqui temos um array ímpar de 5 elementos que dividimos por 2, retornando dois arrays com 2 elementos e um último com apenas um elemento (deixa aquele cara longe!).
- Aqui temos um array de 10 elementos que é dividido por 4, retornando dois arrays com 4 elementos e um último array com 2 elementos.
Ou seja, sempre que o resultado da divisão não for exata, temos o resto no último elemento retornado. As expressões que usei acima do tipo (1..10).to_a nada mais fazem do que converter uma Range em um Array.
O código do método “/” é meio críptico, mas se eu tentar explicar aqui vai ficar meio comprido e vou levar uma bronca, então dêem uma queimada nos neurônios aí. ;-)
Afi! Elegantíssimo!! So não gostei do teu array :( cadê a Claire e o Peter Petrelli ??
require ‘enumerator’
(1..10).to_a.enum_cons(2).to_a
=> [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
Shairon,
Fica um pouquinho diferente, pois o último elemento do subarray é o primeiro elemento do próximo subarray (como no seu próprio exemplo), olha só aplicado no meu exemplo:
%w(hiro ando nikki jessica sylar).enum_cons(2).to_a
=> [[“hiro”, “ando”], [“ando”, “nikki”], [“nikki”, “jessica”], [“jessica”, “sylar”]]
A não ser que alguém ali tenha o poder de duplicar o outro não daria certo. E se você souber de algum spoiler que tenha alguém assim não conta (e olha, só sobraram o Hiro e o Sylar que não foram duplicados) !!! :-)
Só para complementar: o Rails insere um método chamado in_groups_of que nos permite fazer algo do tipo:
%w(hiro ando nikki jessica sylar).in_groups_of(2)
=> [[“hiro”, “ando”], [“nikki”, “jessica”], [“sylar”, nil]]
>> (1..10).to_a.in_groups_of(4)
=> [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, nil, nil]]
Uma pequena diferença ali é que ele completa o array com nil, *se não for passado um segundo parâmetro que especifica como serão completados os elementos faltantes*. Para ter um comportamento similar ao original, seria:
>> %w(hiro ando nikki jessica sylar).in_groups_of(2,false)
=> [[“hiro”, “ando”], [“nikki”, “jessica”], [“sylar”]]
>> %w(hiro ando nikki jessica sylar).in_groups_of(2,false)
=> [[“hiro”, “ando”], [“nikki”, “jessica”], [“sylar”]]
Dá para usar outros preenchimentos também:
>> %w(hiro ando nikki jessica sylar).in_groups_of(2,”who?”)
=> [[“hiro”, “ando”], [“nikki”, “jessica”], [“sylar”, “who?”]]
>> (1..10).to_a.in_groups_of(4,0)
=> [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 0, 0]]
Ops um erro meu
(1..10).to_a.enum_slice(2).to_a
=> [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
Uia, agora ficou melhor de bom! Muito legal!
Menor que isso não dá! :-)
>> require “enumerator”
=> true
>> %w(hiro ando nikki jessica sylar).to_a.enum_slice(2).to_a
=> [[“hiro”, “ando”], [“nikki”, “jessica”], [“sylar”]]
Acho que até dá TaQ ;D~
Tem só uma redundância nos códigos… testei isso no irb:
>> require ‘enumerator’
=> true
>> %w(hiro ando nikki jessica sylar).enum_slice(2).to_a
=> [[“hiro”, “ando”], [“nikki”, “jessica”], [“sylar”]]
>> (1..10).enum_slice(2).to_a
=> [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
espero que esteja certo ;]
abração!
E testando um pouco mais… podemos fazer assim:
>> require ‘enumerator’
=> true
>> class Array
>> def / len
>> enum_slice(len).to_a
>> end
>> end
=> nil
>> class Range
>> def / len
>> enum_slice(len).to_a
>> end
>> end
=> nil
>> %w(hiro ando nikki jessica sylar) / 2
=> [[“hiro”, “ando”], [“nikki”, “jessica”], [“sylar”]]
>> (1..10) / 2
=> [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
;]