How to give depth to arrays?

Hi,

I’m trying to convert an array like [2,3,3,5,4,4] in
[2,[3,3,[[5],4,4]]], but I really can’t figure how to this.
Is there any way to achieve this in Ruby?

Thanks in advance.

Chris M. wrote:

Hi,

I’m trying to convert an array like [2,3,3,5,4,4] in
[2,[3,3,[[5],4,4]]], but I really can’t figure how to this.
Is there any way to achieve this in Ruby?

Thanks in advance.

I once asked a question about multidimensional arrays and I received a
solution like this

irb(main):001:0> array = []
=> []
irb(main):002:0> new_array = [1,2,3]
=> [1, 2, 3]
irb(main):003:0> array << new_array
=> [[1, 2, 3]]
irb(main):004:0> array << 3
=> [[1, 2, 3], 3]
irb(main):005:0> array[0] << 5
=> [1, 2, 3, 5]
irb(main):006:0> array
=> [[1, 2, 3, 5], 3]
irb(main):007:0> array[0] << [5]
=> [1, 2, 3, 5, [5]]
irb(main):008:0> array
=> [[1, 2, 3, 5, [5]], 3]
irb(main):009:0>

I wish this helps
regards

Chris M. wrote:

Hi,

I’m trying to convert an array like [2,3,3,5,4,4] in
[2,[3,3,[[5],4,4]]], but I really can’t figure how to this.
Is there any way to achieve this in Ruby?

I don’t really get the question… do you want to do this automatically?
If yes, how should the mapping look like (i.e. what decides that 3 is 1
level deep, 5 is 4 level deep etc.)?

Cheers,
Peter


http://www.rubyrailways.com
http://scrubyt.org

I don’t really get the question… do you want to do this automatically?
If yes, how should the mapping look like (i.e. what decides that 3 is 1
level deep, 5 is 4 level deep etc.)?

Sorry, my question was missing some important details.
1/ it’s array of numbers only
2/ the first number is the base depth
3/ for every number increase a depth of array is added
so [1,2,4,2] => [1,[2,[[4]],2]]
and [5,5,6] => [5,5,[6]]
4/ and it would be wonderful if it were automatic, by extending the
Array class if possible. The image is a kind of opposite of flatten.

for now I’m trying with the insert/slice! couple, no cute at all & not
really working

class Array
def depthen
base_depth = self[0]
range = [0,0]
in_flag, out_flag = false, false
self.each_index{ |i|
if self[i]>base_depth && !in_flag
in_flag = true;
range[0] = i
end
if self[i] <= base_depth && !out_flag
out_flag = true
range[1] = i-1
end
}
self.insert(range[0], self.slice!(eval(range.join(’…’))) )
end
end

p [2,3,3,5,4,4].depthen => [2,[3,3,5,4,4]]

I hope I’m on the good way, but the code is really ugly

Thank you in advance,
Chris.

Okay, I made it kinda works, clunky and ugly though…

class Array
def max
max = 0;
self.each{ |i| max = i>max ? i : max }
max
end
def min
min = 9999;
self.each{ |i| min = i<min ? i : min }
min
end
def depthen
base_depth = self.min
range = [0,0]
in_flag, out_flag = false, false
self.each_index{ |i|
if self[i]>base_depth && !in_flag
in_flag = true;
range[0] = i
end
if self[i] <= base_depth && !out_flag
out_flag = true
range[1] = i-1
end
}
to_insert = self.slice!(eval(range.join(’…’)))
to_insert.depthen if to_insert.max>to_insert.min
self.insert( range[0], to_insert )
end
end

p [2,3,3,5,4,4].depthen => [2,[3,3,[[5],4,4]]]

I will be really thankful if anybody could help me improve this monster
with nice ruby tricks.

Thank you in advance,
Chris.

On Nov 22, 2007 10:28 AM, Chris M. [email protected] wrote:

min = 9999;
    range[0] = i

end

p [2,3,3,5,4,4].depthen => [2,[3,3,[[5],4,4]]]

I will be really thankful if anybody could help me improve this monster
with nice ruby tricks.

With your code:

[2,3,5,3].depthen # => [2, [3, [[5], 3]]]

Shouldn’t this be:

[2, [3, [[5]], 3]]

?

I’m trying to think of an elegant solution, but I’m kind of slow
today…

Jesus.

On Nov 22, 2007 3:03 PM, Jesús Gabriel y Galán [email protected]
wrote:

Shouldn’t this be:

[2, [3, [[5]], 3]]

?

I’m trying to think of an elegant solution, but I’m kind of slow today…

I managed to get some time at work and this is my first try,
I use a stack to maintain the arrays for each level when you are
going upwards, so you can add to the same array when you go
downwards (makes any sense?):

class Array
def depthen
depth = self[0]
result = []
stack = []
current = result
each do |x|
case depth <=> x
when 0
current << x
when -1
diff = x - depth
value = [x]
tmp = value
(diff - 1).times do
value = [value]
stack.push value
end
current << value
current = tmp
stack.push current
when 1
diff = depth - x + 1
diff.times {current = stack.pop}
current = result if current.nil?
current << x
end
depth = x
end
result
end
end

a = [[2,3,3,4,5,4,4], [2,3,5,3, 2]]
a.each {|x| p x.depthen}

[2, [3, 3, [4, [5], 4, 4]]]
[2, [3, [[5]], 3], 2]

Have fun,

Jesus.

Eric I. wrote:

Others, including Chris M., have interpreted the task as follows:

p [2,3,3,5,4,4].depthen => [2,[3,3,[[5],4,4]]]

But that doesn’t seem right to me, since the element 2 is at a depth
of 1 and not 2.

quoth Chris M.:

Others, including Chris M., have interpreted the task as follows:

p [2,3,3,5,4,4].depthen => [2,[3,3,[[5],4,4]]]

But that doesn’t seem right to me, since the element 2 is at a depth
of 1 and not 2. I would think the result should be:

 [[2,[3,3,[[5],4,4]]]]

Anyway, here’s a solution which handles my interpretation:

class Array
def depthen
result = []

self.each do |depth|
  array_end = result
  (depth - 1).times do
    array_end << [] unless array_end.last.kind_of? Array
    array_end = array_end.last
  end
  array_end << depth
end

result

end
end

And here’s what it does:

p [2, 3, 3, 5, 4, 1, 4, 6, 10, 2].depthen

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

To change it to the other interpretation, just change “depth - 1” to
“depth - 2”. And then, presumably, the array depthen is called on
shouldn’t have any "1"s in it (although even they’re handled
“gracefully” with the depthen method provided).

Eric

====

Are you interested in on-site Ruby training that uses well-designed,
real-world, hands-on exercises? http://LearnRuby.com

On Nov 22, 1:39 pm, Sebastian H. [email protected]
wrote:

quoth Chris M.:

the first number is the base depth

Thank you, Sebastian! I lost track of that.

OK, here we go, then:

class Array
def depthen
base_depth = first
result = []

each do |depth|
  array_end = result
  (depth - base_depth).times do
    array_end << [] unless array_end.last.kind_of? Array
    array_end = array_end.last
  end
  array_end << depth
end

result

end
end

Eric

====

Interested in hands-on, on-site Ruby training? See http://LearnRuby.com
for information about a well-reviewed class.

On Nov 22, 2007 7:39 PM, Sebastian H. [email protected]
wrote:

Eric I. wrote:

Others, including Chris M., have interpreted the task as follows:

p [2,3,3,5,4,4].depthen => [2,[3,3,[[5],4,4]]]

But that doesn’t seem right to me, since the element 2 is at a depth
of 1 and not 2.

quoth Chris M.:

the first number is the base depth

Yes, that’s what I based my solution on. Afterwards I saw in his
solution that he used the min of the array which makes more sense…

Jesus.

I will be really thankful if anybody could help me improve this monster
with nice ruby tricks.

My first impression is that the code should probably achieve its goals
in some other way than it’s currently attempting. Trying something
this intricate often means setting yourself up for failure. It might
be possible to use trees or something similar instead, depending on
the nature of the problem you’ve decided to solve.


Giles B.

Podcast: http://hollywoodgrit.blogspot.com
Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org
Tumblelog: http://giles.tumblr.com

Wow!
Thanks everybody & Thank you so much Eric

class Array
def depthen
base_depth = first
result = []

each do |depth|
  array_end = result
  (depth - base_depth).times do
    array_end << [] unless array_end.last.kind_of? Array
    array_end = array_end.last
  end
  array_end << depth
end

result

end
end

I couldn’t have dreamt a shorter way to achieve this, You really are a
Genius.
So short and nice! This must be what they call the ruby way I think :wink:

Chris.