[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

how to split an array in sub arrays of the same length

Paolo Bacchilega

7/20/2006 6:54:00 AM

Hi,

Is there a way to split an array in sub arrays of the same length, that
is :

[ 1, 2, 3, 4, 5, 6, 7, 8 ].unknown_function(3)

that returns:

[ [1, 2, 3], [4, 5, 6], [7, 8] ]


thanks in advance.

13 Answers

WATANABE Hirofumi

7/20/2006 7:24:00 AM

0

Hi,

Paolo Bacchilega <paolo.bacchilega@libero.it> writes:

> Is there a way to split an array in sub arrays of the same length, that
> is :
>
> [ 1, 2, 3, 4, 5, 6, 7, 8 ].unknown_function(3)
>
> that returns:
>
> [ [1, 2, 3], [4, 5, 6], [7, 8] ]

% irb --prompt simple
>> require 'enumerator'
=> true
>> [ 1, 2, 3, 4, 5, 6, 7, 8 ].enum_slice(3).to_a
=> [[1, 2, 3], [4, 5, 6], [7, 8]]

--
eban

Peña, Botp

7/20/2006 7:35:00 AM

0

fr paulo:
# Is there a way to split an array in sub arrays of the same
# length, that
# is :
#
# [ 1, 2, 3, 4, 5, 6, 7, 8 ].unknown_function(3)
# that returns:
# [ [1, 2, 3], [4, 5, 6], [7, 8] ]

irb(main):021:0> x
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):022:0> y=[]
=> []
irb(main):023:0> x.each_slice(3){|s| y << s}
=> nil
irb(main):024:0> y
=> [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

kind regards -botp

Morton Goldberg

7/20/2006 8:30:00 AM

0

Although you could use Enumerator::each_slice as others have
suggested, it might be simpler to augment Array with a partition
function.

class Array

def partition(n, r=[])
raise ArgumentError if n <= 0
if n <= size then
r << first(n)
last(size - n).partition(n, r)
else
r << self unless empty?
return r
end
end

end

p [ 1, 2, 3, 4, 5, 6, 7, 8 ].partition(1) => [[1], [2], [3], [4],
[5], [6], [7], [8]]
p [ 1, 2, 3, 4, 5, 6, 7, 8 ].partition(3) => [[1, 2, 3], [4, 5, 6],
[7, 8]]
p [ 1, 2, 3, 4, 5, 6, 7, 8 ].partition(4) => [[1, 2, 3, 4], [5, 6, 7,
8]]
p [ 1, 2, 3, 4, 5, 6, 7, 8 ].partition(6) => [[1, 2, 3, 4, 5, 6], [7,
8]]
p [ 1, 2, 3, 4, 5, 6, 7, 8 ].partition(8) => [[1, 2, 3, 4, 5, 6, 7, 8]]
p [ 1, 2, 3, 4, 5, 6, 7, 8 ].partition(10) => [[1, 2, 3, 4, 5, 6, 7, 8]]
p [ 1, 2, 3, 4, 5, 6, 7, 8 ].partition(-2) =>
untitled text:6:in `partition': ArgumentError (ArgumentError)
from untitled text:24

Hope this is helps.
Regards, Morton

On Jul 20, 2006, at 2:55 AM, Paolo Bacchilega wrote:

> Hi,
>
> Is there a way to split an array in sub arrays of the same length,
> that
> is :
>
> [ 1, 2, 3, 4, 5, 6, 7, 8 ].unknown_function(3)
>
> that returns:
>
> [ [1, 2, 3], [4, 5, 6], [7, 8] ]
>
>
> thanks in advance.


Paolo Bacchilega

7/20/2006 12:05:00 PM

0

Il giorno gio, 20/07/2006 alle 06.53 +0000, Paolo Bacchilega ha scritto:
> Hi,
>
> Is there a way to split an array in sub arrays of the same length, that
> is :
>
> [ 1, 2, 3, 4, 5, 6, 7, 8 ].unknown_function(3)
>
> that returns:
>
> [ [1, 2, 3], [4, 5, 6], [7, 8] ]
>
>
> thanks in advance.

thanks to all for responding.

William James

7/20/2006 8:31:00 PM

0

Paolo Bacchilega wrote:
> Hi,
>
> Is there a way to split an array in sub arrays of the same length, that
> is :
>
> [ 1, 2, 3, 4, 5, 6, 7, 8 ].unknown_function(3)
>
> that returns:
>
> [ [1, 2, 3], [4, 5, 6], [7, 8] ]
>
>
> thanks in advance.

Always remember that a program without inject is a
pointless program.

[ 1, 2, 3, 4, 5, 6, 7, 8 ].inject([[]]){|a,x|
a.last.size<3 ? a.last << x : a << [x]; a }

Gavin Kistner

7/20/2006 8:39:00 PM

0

Paolo Bacchilega wrote:
> Is there a way to split an array in sub arrays of the same length, that

Stolen from the facets[1] extensions for Arrays[2]:

class Array
def each_slice(n=nil, &yld)
n = yld.arity.abs unless n
i=0
while i < self.length
yld.call(*self.slice(i,n))
i+=n
end
end
end

[1] http://facets.ruby...
[2] http://facets.ruby...api/core/classes/Array.html#M000163

Logan Capaldo

7/21/2006 3:28:00 AM

0


On Jul 20, 2006, at 4:40 PM, Phrogz wrote:

> Paolo Bacchilega wrote:
>> Is there a way to split an array in sub arrays of the same length,
>> that
>
> Stolen from the facets[1] extensions for Arrays[2]:
>
> class Array
> def each_slice(n=nil, &yld)
> n = yld.arity.abs unless n
> i=0
> while i < self.length
> yld.call(*self.slice(i,n))
> i+=n
> end
> end
> end
>
> [1] http://facets.ruby...
> [2] http://facets.ruby...api/core/classes/Array.html#M000163
>
>

This is in enumerator, enumerator comes with ruby. Do we really need
an "Optimized for Array" version? (That is its purpose according to
the docs.)

Well surprising to me, there really is a noticeable speed difference.
I gues sit makes sense, each_slice in enumerator.c is written to use
each, and not just call to_a first either. (Which makes sense, Files
are Enumerables after all, maybe you want it in chunks of N lines at
a time. You wouldn't want to have to slurp the whole file into memory
just to do that).

I wonder if we can get this each_slice stuck in the standard lib for
Array.



% cat enumerator_vs_facets.rb
#!/usr/bin/env ruby
require 'enumerator'
require 'benchmark'

class Array
def facets_each_slice(n=nil, &yld)
n = yld.arity.abs unless n
i=0
while i < self.length
yld.call(*self.slice(i,n))
i+=n
end
end
end

arrays = [ (1..97).to_a, (0..99).to_a, ["hello", "world"] ]
N = 1000
Benchmark.bmbm do |bm|
bm.report("Facets: ") do
N.times do
arrays.each do |array|
array.facets_each_slice(3) { |*x| "#{x}" }
end
end
end

bm.report("Enumerator: ") do
N.times do
arrays.each do |array|
array.each_slice(3) { |*x| "#{x}" }
end
end
end
end



% ruby enumerator_vs_facets.rb
Rehearsal ------------------------------------------------
Facets: 1.250000 0.010000 1.260000 ( 1.364671)
Enumerator: 1.380000 0.010000 1.390000 ( 1.442132)
--------------------------------------- total: 2.650000sec

user system total real
Facets: 1.250000 0.010000 1.260000 ( 1.315879)
Enumerator: 1.390000 0.010000 1.400000 ( 1.447592)


Bernard Kenik

7/29/2006 2:09:00 AM

0


Logan Capaldo wrote:
> % cat enumerator_vs_facets.rb
> #!/usr/bin/env ruby
> require 'enumerator'
> require 'benchmark'
>
> class Array
> def facets_each_slice(n=nil, &yld)
> n = yld.arity.abs unless n
> i=0
> while i < self.length
> yld.call(*self.slice(i,n))
> i+=n
> end
> end
> end
>
> arrays = [ (1..97).to_a, (0..99).to_a, ["hello", "world"] ]
> N = 1000
> Benchmark.bmbm do |bm|
> bm.report("Facets: ") do
> N.times do
> arrays.each do |array|
> array.facets_each_slice(3) { |*x| "#{x}" }
> end
> end
> end
>
> bm.report("Enumerator: ") do
> N.times do
> arrays.each do |array|
> array.each_slice(3) { |*x| "#{x}" }
> end
> end
> end
> end
>
>
>
> % ruby enumerator_vs_facets.rb
> Rehearsal ------------------------------------------------
> Facets: 1.250000 0.010000 1.260000 ( 1.364671)
> Enumerator: 1.380000 0.010000 1.390000 ( 1.442132)
> --------------------------------------- total: 2.650000sec
>
> user system total real
> Facets: 1.250000 0.010000 1.260000 ( 1.315879)
> Enumerator: 1.390000 0.010000 1.400000 ( 1.447592)

I believe the OP asked how to split an array in "x" sub arrays of equal
length.
To me, it appears that the response show how to partition an array into
sub arrays of "y" elements.

The following method does what the OP asked for, as far as I read it.

class Array
def split(n, b=[], d=[])
#########################################################################
# evenly split array 'a' into 'n' sub arrays
#########################################################################
if self.size == 0 or n <= 0
b = nil
elsif n == 1
b = *self
else
# determine how many elements of the array should go in each sub
arrays
buckets = n
length = self.size
while buckets > 0
elements = length / buckets + (length % buckets > 0 ? 1 : 0)
d << elements
length -= elements
buckets -= 1
end
# p d

# evenly distribute array elements into an array with 'n' sub arrays
start = 0 # start
0.upto(n-1) do |idx|
len = d[idx]
b[idx] = *self.slice(start,len)
start += len
end
end
b
end
end

Bernard Kenik

7/29/2006 2:48:00 AM

0

bbiker wrote:
> I believe the OP asked how to split an array in "x" sub arrays of equal
> length.
> To me, it appears that the response show how to partition an array into
> sub arrays of "y" elements.
>
> The following method does what the OP asked for, as far as I read it.
>
> class Array
> def split(n, b=[], d=[])
> #########################################################################
> # evenly split array 'a' into 'n' sub arrays
> #########################################################################
> if self.size == 0 or n <= 0
> b = nil
> elsif n == 1
> b = *self
> else
> # determine how many elements of the array should go in each sub
> arrays
> buckets = n
> length = self.size
> while buckets > 0
> elements = length / buckets + (length % buckets > 0 ? 1 : 0)
> d << elements
> length -= elements
> buckets -= 1
> end
> # p d
>
> # evenly distribute array elements into an array with 'n' sub arrays
> start = 0 # start
> 0.upto(n-1) do |idx|
> len = d[idx]
> b[idx] = *self.slice(start,len)
> start += len
> end
> end
> b
> end
> end

Sorry, but I pressed the Post message button too soon.

c =
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23].split(5)
=>

[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18,
19], [20, 21, 22, 23]]

Note that the first 3 sub arrays contain 5 elements and the last 2 sub
arrays contain 4 elements.

I am a Ruby newbie and would appreciate a critique on the method I
posted.

Thank You

William James

7/29/2006 8:18:00 AM

0

bbiker wrote:
> bbiker wrote:
> > I believe the OP asked how to split an array in "x" sub arrays of equal
> > length.
> > To me, it appears that the response show how to partition an array into
> > sub arrays of "y" elements.
> >
> > The following method does what the OP asked for, as far as I read it.
> >
> > class Array
> > def split(n, b=[], d=[])
> > #########################################################################
> > # evenly split array 'a' into 'n' sub arrays
> > #########################################################################
> > if self.size == 0 or n <= 0
> > b = nil
> > elsif n == 1
> > b = *self
> > else
> > # determine how many elements of the array should go in each sub
> > arrays
> > buckets = n
> > length = self.size
> > while buckets > 0
> > elements = length / buckets + (length % buckets > 0 ? 1 : 0)
> > d << elements
> > length -= elements
> > buckets -= 1
> > end
> > # p d
> >
> > # evenly distribute array elements into an array with 'n' sub arrays
> > start = 0 # start
> > 0.upto(n-1) do |idx|
> > len = d[idx]
> > b[idx] = *self.slice(start,len)
> > start += len
> > end
> > end
> > b
> > end
> > end
>
> Sorry, but I pressed the Post message button too soon.
>
> c =
> [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23].split(5)
> =>
>
> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18,
> 19], [20, 21, 22, 23]]
>
> Note that the first 3 sub arrays contain 5 elements and the last 2 sub
> arrays contain 4 elements.
>
> I am a Ruby newbie and would appreciate a critique on the method I
> posted.
>
> Thank You

class Array
def split n
count , fat_ones = self.size / n , self.size % n
self.inject( [[]] ){ |a,e|
a.last.size < count + ( a.size <= fat_ones ? 1 : 0 ) ?
a.last << e : a << [e] ; a }
end
end

a = (1..23).to_a
p a.split(5)
p a