How to give depth to arrays?

C

Chris Morales

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.
 
S

Shuaib Zahda

Chris said:
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
 
P

Peter Szinek

Chris said:
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
 
C

Chris Morales

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>base_depth && !in_flag
in_flag = true;
range[0] = i
end
if self <= 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.
 
C

Chris Morales

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>base_depth && !in_flag
in_flag = true;
range[0] = i
end
if self <= 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.
 
J

Jesús Gabriel y Galán

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>base_depth && !in_flag
in_flag = true;
range[0] = i
end
if self <= 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.


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.
 
J

Jesús Gabriel y Galán

p [2,3,3,5,4,4].depthen =3D> [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 # =3D> [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...

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 =3D self[0]
result =3D []
stack =3D []
current =3D result
each do |x|
case depth <=3D> x
when 0
current << x
when -1
diff =3D x - depth
value =3D [x]
tmp =3D value
(diff - 1).times do
value =3D [value]
stack.push value
end
current << value
current =3D tmp
stack.push current
when 1
diff =3D depth - x + 1
diff.times {current =3D stack.pop}
current =3D result if current.nil?
current << x
end
depth =3D x
end
result
end
end


a =3D [[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.
 
E

Eric I.

Others, including Chris Morales, 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
 
S

Sebastian Hungerecker

Eric said:
Others, including Chris Morales, 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 Morales:
 
E

Eric I.

quoth Chris Morales:

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.
 
J

Jesús Gabriel y Galán

Eric said:
Others, including Chris Morales, 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 Morales:

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.
 
G

Giles Bowkett

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 Bowkett

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

Chris Morales

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 ;)

Chris.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,270
Messages
2,571,353
Members
48,038
Latest member
HunterDela

Latest Threads

Top