[Q] how to unflatten a flat-array

(SHIGETOMI, Takuhiko) #1

dear guys,

i am seeking a smart way to do ...

   [ 1, 2, 3, 4, 5, 6, ... ] => [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], ... ]

especialy, the way hopefully will work safety when the source array's
size is odd or zero.

···

--
<name species-designation="5618" default-lang="ja_JP">SHIGETOMI,Takuhiko</name>
<contact medium="email">tshiget1@gw.nsw.co.jp</contact>
<location federational-alias="/galaxy/alpha-quadrant/sector-001/earth/">
  /void/3d/universe/milkyway-galaxy/orion's-arm/sol-solar-system/3rd-planet/fareast/jp/tky/
</location>
<hail>resistance is futile.</hail>

(HAL 9000) #2

SHIGETOMI, Takuhiko wrote:

dear guys,

i am seeking a smart way to do ...

   [ 1, 2, 3, 4, 5, 6, ... ] => [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], ... ]

especialy, the way hopefully will work safety when the source array's
size is odd or zero.

I have used something like:

   arr = array.dup
   result = []
   while ! arr.empty?
     result << arr.slice!(0..1)
   end

Would that work for you?

Hal

(David A. Black) #3

Hi --

dear guys,

i am seeking a smart way to do ...

  [ 1, 2, 3, 4, 5, 6, ... ] => [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], ... ]

especialy, the way hopefully will work safety when the source array's
size is odd or zero.

I've got a method from long ago that might fit:

   class Array # or do it as a module, or whatever
     def in_slices_of(n)
       res = []
       0.step(size - 1, n) do |i|
         s = slice(i...i + n)
         yield s if block_given?
         res.push s
       end
       res
     end
   end

   [1,2,3,4,5,6].in_slices_of(2) # => [[1, 2], [3, 4], [5, 6]]
   [1,2,3,4,5,6].in_slices_of(3) # => [[1, 2, 3], [4, 5, 6]]

It handles odd numbers by putting whatever's left over in its own
array:

   [1,2,3,4,5,6,7].in_slices_of(2) # => [[1, 2], [3, 4], [5, 6], [7]]

(and note that it yields each slice too).

In 1.9 you can do:

   irb(main):015:0> [1,2,3,4,5,6].enum_slice(2).map {|x| x }
   => [[1, 2], [3, 4], [5, 6]]

which handles odd numbers the same way. (I can't seem to get it to
return the desired result without doing the map operation.)

David

···

On Mon, 29 Aug 2005, SHIGETOMI, Takuhiko wrote:

--
David A. Black
dblack@wobblini.net

(James Edward Gray II) #4

Pretty hackish but:

irb(main):001:0> arr = [ 1, 2, 3, 4, 5, 6]
=> [1, 2, 3, 4, 5, 6]
irb(main):011:0> arr << nil unless arr.size % 2 == 0
=> nil
irb(main):012:0> Hash[*arr].to_a.sort
=> [[1, 2], [3, 4], [5, 6]]

I was just playing around. I like David's in_slices() method much better.

James Edward Gray II

···

On Aug 28, 2005, at 8:50 PM, SHIGETOMI, Takuhiko wrote:

dear guys,

i am seeking a smart way to do ...

   [ 1, 2, 3, 4, 5, 6, ... ] => [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], ... ]

especialy, the way hopefully will work safety when the source array's
size is odd or zero.

(Robert K.) #5

dear guys,

i am seeking a smart way to do ...

   [ 1, 2, 3, 4, 5, 6, ... ] => [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], ... ]

especialy, the way hopefully will work safety when the source array's
size is odd or zero.

This is a pretty much straightforward implementation:

res=[]; 0.step(a.length - 1,2) {|i| res << [a[i],a[i+1]]}; res

=> [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]

Kind regards

robert

···

2005/8/29, SHIGETOMI, Takuhiko <tshiget1@gw.nsw.co.jp>:

(W. James) #6

SHIGETOMI, Takuhiko wrote:

dear guys,

i am seeking a smart way to do ...

   [ 1, 2, 3, 4, 5, 6, ... ] => [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], ... ]

especialy, the way hopefully will work safety when the source array's
size is odd or zero.

ary = [1,2,3,4,5,6,7,8]
f=nil
t=ary.partition{f=!f}
p t[0].zip(t[1])

(Linus Sellberg) #7

TIMTOWTDI:

def slicer arr, n
   arr = arr.dup
   arr.each_index {|i| arr[i...(i + n)] = [arr[i...(i + n)]] }
end

x = [1,2,3,4,5,6,7]

slicer x,3
=> [[1, 2, 3], [4, 5, 6], [7]]

···

On 8/29/05, SHIGETOMI, Takuhiko <tshiget1@gw.nsw.co.jp> wrote:

   [ 1, 2, 3, 4, 5, 6, ... ] => [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], ... ]

(SHIGETOMI, Takuhiko) #8

greetings, Hal. gratitude to you.

   arr = array.dup
   result = []
   while ! arr.empty?
     result << arr.slice!(0..1)
   end

looks like nice to me.
please let me exec it and repot the result to you later.
(sorry, i am now screwed up in my business.)

···

--
<name species-designation="5618" default-lang="ja_JP">SHIGETOMI,Takuhiko</name>
<contact medium="email">tshiget1@gw.nsw.co.jp</contact>
<location federational-alias="/galaxy/alpha-quadrant/sector-001/earth/">
  /void/3d/universe/milkyway-galaxy/orion's-arm/sol-solar-system/3rd-planet/fareast/jp/tky/
</location>
<hail>resistance is futile.</hail>

(SHIGETOMI, Takuhiko) #9

greetings, David. how nice it is!

I've got a method from long ago that might fit:

   class Array # or do it as a module, or whatever
     def in_slices_of(n)
       res = []
       0.step(size - 1, n) do |i|
         s = slice(i...i + n)
         yield s if block_given?
         res.push s
       end
       res
     end
   end

   [1,2,3,4,5,6].in_slices_of(2) # => [[1, 2], [3, 4], [5, 6]]
   [1,2,3,4,5,6].in_slices_of(3) # => [[1, 2, 3], [4, 5, 6]]

It handles odd numbers by putting whatever's left over in its own
array:

   [1,2,3,4,5,6,7].in_slices_of(2) # => [[1, 2], [3, 4], [5, 6], [7]]

quick question. (sorry, i am still screwed up.)
will the yieldee ( = the block ) 's 2nd parameter be nil at the end of
the case of odd number as above ?

···

--
<name species-designation="5618" default-lang="ja_JP">SHIGETOMI,Takuhiko</name>
<contact medium="email">tshiget1@gw.nsw.co.jp</contact>
<location federational-alias="/galaxy/alpha-quadrant/sector-001/earth/">
  /void/3d/universe/milkyway-galaxy/orion's-arm/sol-solar-system/3rd-planet/fareast/jp/tky/
</location>
<hail>resistance is futile.</hail>

(SHIGETOMI, Takuhiko) #10

greeting James. what an intriguing way!

irb(main):001:0> arr = [ 1, 2, 3, 4, 5, 6]
=> [1, 2, 3, 4, 5, 6]
irb(main):011:0> arr << nil unless arr.size % 2 == 0
=> nil
irb(main):012:0> Hash[*arr].to_a.sort
=> [[1, 2], [3, 4], [5, 6]]

for me, as a beginner of ruby,
this is a fascinating black magic.
i will study hard to let it be white. :slight_smile:

···

--
<name species-designation="5618" default-lang="ja_JP">SHIGETOMI,Takuhiko</name>
<contact medium="email">tshiget1@gw.nsw.co.jp</contact>
<location federational-alias="/galaxy/alpha-quadrant/sector-001/earth/">
  /void/3d/universe/milkyway-galaxy/orion's-arm/sol-solar-system/3rd-planet/fareast/jp/tky/
</location>
<hail>resistance is futile.</hail>

(SHIGETOMI, Takuhiko) #11

greetings, William. i'm sorry, your way is beyond my light-weight brain.

ary = [1,2,3,4,5,6,7,8]
f=nil
t=ary.partition{f=!f}
p t[0].zip(t[1])

but it works...

$ irb
irb(main):001:0> ary = [1,2,3,4,5,6,7,8]
=> [1, 2, 3, 4, 5, 6, 7, 8]
irb(main):002:0> f=nil
=> nil
irb(main):003:0> t=ary.partition{f=!f}
=> [[1, 3, 5, 7], [2, 4, 6, 8]]
irb(main):004:0> p t[0].zip(t[1])
[[1, 2], [3, 4], [5, 6], [7, 8]]
=> nil

i'd like you use a terrestrial language, or beam me your universal
translator. :slight_smile:

···

--
<name species-designation="5618" default-lang="ja_JP">SHIGETOMI,Takuhiko</name>
<contact medium="email">tshiget1@gw.nsw.co.jp</contact>
<location federational-alias="/galaxy/alpha-quadrant/sector-001/earth/">
  /void/3d/universe/milkyway-galaxy/orion's-arm/sol-solar-system/3rd-planet/fareast/jp/tky/
</location>
<hail>resistance is futile.</hail>

(SHIGETOMI, Takuhiko) #12

greetings, Robert. thank you, it does make sense to me.

>> res=[]; 0.step(a.length - 1,2) {|i| res << [a[i],a[i+1]]}; res
=> [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]

i know that an yieldee is 100% passive to its yielder, but i often feel
desire to let it fetch to the next/previous yielded object from inside
the yieldee.

don't you know any cool way to do this in ruby?

···

--
<name species-designation="5618" default-lang="ja_JP">SHIGETOMI,Takuhiko</name>
<contact medium="email">tshiget1@gw.nsw.co.jp</contact>
<location federational-alias="/galaxy/alpha-quadrant/sector-001/earth/">
  /void/3d/universe/milkyway-galaxy/orion's-arm/sol-solar-system/3rd-planet/fareast/jp/tky/
</location>
<hail>resistance is futile.</hail>

(David A. Black) #13

Hi --

···

On Mon, 29 Aug 2005, SHIGETOMI, Takuhiko wrote:

greetings, David. how nice it is!

I've got a method from long ago that might fit:

   class Array # or do it as a module, or whatever
     def in_slices_of(n)
       res = []
       0.step(size - 1, n) do |i|
         s = slice(i...i + n)
         yield s if block_given?
         res.push s
       end
       res
     end
   end

   [1,2,3,4,5,6].in_slices_of(2) # => [[1, 2], [3, 4], [5, 6]]
   [1,2,3,4,5,6].in_slices_of(3) # => [[1, 2, 3], [4, 5, 6]]

It handles odd numbers by putting whatever's left over in its own
array:

   [1,2,3,4,5,6,7].in_slices_of(2) # => [[1, 2], [3, 4], [5, 6], [7]]

quick question. (sorry, i am still screwed up.)
will the yieldee ( = the block ) 's 2nd parameter be nil at the end of
the case of odd number as above ?

Yes:

   [1,2,3,4,5,6,7].in_slices_of(2).map {|x,y| [x,y]}
    => [[1, 2], [3, 4], [5, 6], [7, nil]]

I don't think there's much choice. (You could of course just catch
each inner array in one variable.)

David

--
David A. Black
dblack@wobblini.net

(Gene Tani) #14

require 'enumerator'
accum=[]
(1..10).each_slice(3) { |sl| accum << sl}
p accum

SHIGETOMI, Takuhiko wrote:

···

greeting James. what an intriguing way!

irb(main):001:0> arr = [ 1, 2, 3, 4, 5, 6]
=> [1, 2, 3, 4, 5, 6]
irb(main):011:0> arr << nil unless arr.size % 2 == 0
=> nil
irb(main):012:0> Hash[*arr].to_a.sort
=> [[1, 2], [3, 4], [5, 6]]

for me, as a beginner of ruby,
this is a fascinating black magic.
i will study hard to let it be white. :slight_smile:

--
<name species-designation="5618" default-lang="ja_JP">SHIGETOMI,Takuhiko</name>
<contact medium="email">tshiget1@gw.nsw.co.jp</contact>
<location federational-alias="/galaxy/alpha-quadrant/sector-001/earth/">
  /void/3d/universe/milkyway-galaxy/orion's-arm/sol-solar-system/3rd-planet/fareast/jp/tky/
</location>
<hail>resistance is futile.</hail>

(Robert K.) #15

No, not generally. With arrays you can use #each_with_index and in
the general case of Enumerable you can use inject to access the last
element, along the lines

enum.inject {|last, current| .... ; current}

Kind regards

robert

···

2005/8/29, SHIGETOMI, Takuhiko <tshiget1@gw.nsw.co.jp>:

greetings, Robert. thank you, it does make sense to me.

> >> res=[]; 0.step(a.length - 1,2) {|i| res << [a[i],a[i+1]]}; res
> => [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]

i know that an yieldee is 100% passive to its yielder, but i often feel
desire to let it fetch to the next/previous yielded object from inside
the yieldee.

don't you know any cool way to do this in ruby?

(Robert K.) #16

greetings, William. i'm sorry, your way is beyond my light-weight brain.

Although I'm not the author I can jump in with an explanation.

> ary = [1,2,3,4,5,6,7,8]
> f=nil
> t=ary.partition{f=!f}
> p t[0].zip(t[1])

but it works...

#partition puts contents of an Enumerable into two arrays depending on
the boolean result of a block. For example:

(0...10).partition {|x| x % 2 == 0}

=> [[0, 2, 4, 6, 8], [1, 3, 5, 7, 9]]

The code above just toggles a flag (f) on each evaluation of the block
thus putting elements into the first and second array returned
interchangingly.

Array#zip basically iterates two array in lock step. So the first
partition contains x elements and the second partition contains y
elements and #zip creates pairs [x,y] from them.

Although I like this solution because of its cuteness and shortness,
it has the disadvantage of creating two intermediate arrays. That
might or might not be a problem in your case - depending on the array
sizes involved. HTH

Kind regards

robert

···

2005/8/29, SHIGETOMI, Takuhiko <tshiget1@gw.nsw.co.jp>:

(Daniel Brockman) #17

"SHIGETOMI, Takuhiko" <tshiget1@gw.nsw.co.jp> writes:

i know that an yieldee is 100% passive to its yielder, but
i often feel desire to let it fetch to the next/previous
yielded object from inside the yieldee.

don't you know any cool way to do this in ruby?

You can't easily go backwards, but skipping to the next is
as easy as saying `next'.

···

--
Daniel Brockman <daniel@brockman.se>

(Simon Kröger) #18

SHIGETOMI, Takuhiko wrote:

greetings, William. i'm sorry, your way is beyond my light-weight brain.

ary = [1,2,3,4,5,6,7,8]
f=nil
t=ary.partition{f=!f}
p t[0].zip(t[1])

but it works...

$ irb
irb(main):001:0> ary = [1,2,3,4,5,6,7,8]
=> [1, 2, 3, 4, 5, 6, 7, 8]
irb(main):002:0> f=nil
=> nil
irb(main):003:0> t=ary.partition{f=!f}
=> [[1, 3, 5, 7], [2, 4, 6, 8]]
irb(main):004:0> p t[0].zip(t[1])
[[1, 2], [3, 4], [5, 6], [7, 8]]
=> nil

i'd like you use a terrestrial language, or beam me your universal
translator. :slight_smile:

Muhahaha...

p ary.zip((0...ary.size).to_a).partition{|o|(o[1]%2).zero?}.
map{|a|a.transpose[0]}

erm, sorry, could not resist :slight_smile:

But transpose make the example above shorter (and perhaps even
more readable):

f=nil
p ary.partition{f=!f}.transpose

cheers

Simon

(SHIGETOMI, Takuhiko) #19

greetings, Gene. i have felt that yours is quite a ruby-ish way.

require 'enumerator'
accum=[]
(1..10).each_slice(3) { |sl| accum << sl}
p accum

let me put it into my treasure box.
this is quite useful at the case of that the enumeratee is surely
innocent.

···

--
<name species-designation="5618" default-lang="ja_JP">SHIGETOMI,Takuhiko</name>
<contact medium="email">tshiget1@gw.nsw.co.jp</contact>
<location federational-alias="/galaxy/alpha-quadrant/sector-001/earth/">
  /void/3d/universe/milkyway-galaxy/orion's-arm/sol-solar-system/3rd-planet/fareast/jp/tky/
</location>
<hail>resistance is futile.</hail>

(SHIGETOMI, Takuhiko) #20

greetings, Daniel. true. 'next' works.

You can't easily go backwards, but skipping to the next is
as easy as saying `next'.

on the other hand, and as your reference 'cannot easyily go backwards',
'next' forgets current object unless any variable on outside of the
yieldee block.

how about writing a special yielder like as below ..

    any-enumerable-object.sliding_each do |prev,this,next|
      ...
    end

- could be really useful?
- any other good name?

/void/3d/universe/milky-way-galaxy/orion-arm/sol-solar-system/3rd-planet/fareast/jp/tky/shigetomi.takuhiko.5618