[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Managing Hierarchical Tree-Like Data

x1

10/31/2006 1:45:00 AM

Team:
I'm looking for a pragmatic way of creating a tree from a list of
items without knowing the depth of each.

For example:

max_depth = 4 #considers each unique item below the depth of 4 to be one
item_tree = {}
["CarRedFast",
"CarGreenSlow",
"Car",
"CarRedFastAgileSadCheeseBurger",
"CarRedFastAgileHappyJoy",
"GreenApplePie",
"GreenApple"
].each do |i|
items = i.gsub(/[A-Z][a-z]/) {|i| "_" + i}.gsub(/^_/, "").split("_")
end

This builds an array from items based on the case but many times, I
have needed to display this data in tree form as such:

#############################
# Desired output:
Car(2)
Red(1)
Fast(1)
Agile(2)
HappyJoy
SadCheeseBurger
Green(1)
Slow(0)
Green(1)
Apple(1)
Pie(0)
###############################


I've come across this numerous times and am pretty sure there's a
better way of doing it.

This is pretty much what I have now and it feels SO wrong to write!

#This just feels horrible writing
item_tree = {}
["CarRedFast",
"CarGreenSlow",
"Car",
"CarRedFastAgileSadCheeseBurger",
"CarRedFastAgileHappyJoy",
"GreenApplePie",
"GreenApple"
].each do |i|
items = i.gsub(/[A-Z][a-z]/) {|i| "_" + i}.gsub(/^_/, "").split("_")
items.each do |item|
if item_tree.include? item[0]
if item_tree[item[0]].include? item[1]
#yadadada
else
item_tree[item[0]][item[1]] = {}
end
else
item_tree[item[0]] = {}
end
end
end



Please.. Any suggestions at all.. All comments welcome!! TIA

15 Answers

Gavin Kistner

10/31/2006 2:49:00 AM

0

x1 wrote:
> Team:
> I'm looking for a pragmatic way of creating a tree from a list of
> items without knowing the depth of each.

How about this:
class Hash
def as_tree( depth=0 )
map{ |k,subtree|
me = " "*depth + "#{k} (#{subtree.length})"
if subtree.empty?
me
else
[ me, subtree.as_tree( depth+1 ) ]
end
}.flatten.join( "\n" )
end
end

hash_of_hashes = lambda { Hash.new {|h,k| h[k] = hash_of_hashes.call} }
item_tree = hash_of_hashes.call

items = [ "CarRedFast", "CarGreenSlow", "Car",
"CarRedFastAgileSadCheeseBurger", "CarRedFastAgileHappyJoy",
"GreenApplePie", "GreenApple" ]
items.each do |item|
current = item_tree
item.scan( /[A-Z][a-z]+/ ).each{ |piece|
current = current[ piece ]
}
end

puts item_tree.as_tree
#=> Green (1)
#=> Apple (1)
#=> Pie (0)
#=> Car (2)
#=> Red (1)
#=> Fast (1)
#=> Agile (2)
#=> Sad (1)
#=> Cheese (1)
#=> Burger (0)
#=> Happy (1)
#=> Joy (0)
#=> Green (1)
#=> Slow (0)

Paul Lutus

10/31/2006 3:04:00 AM

0

x1 wrote:

/ ...

> Please.. Any suggestions at all..

Sure, no problem. I could write an example of a hash-based tree data
structure that would print itself out in a logical way, but I am having a
problem with your data.

Could you provide a better data example, one that shows its hierarchical
nature more clearly?

In the meantime:

-----------------------------------------

#!/usr/bin/ruby -w

# Step 1: create some sample data

array = [
[ "animal","fish","shark" ],
[ "animal","fish","trout" ],
[ "animal","fish","big","whale shark" ],
[ "animal","moose" ],
[ "animal","bear" ],
[ "animal","small","squirrel" ],
[ "plant","cactus" ],
[ "plant","corn" ],
[ "plant","daisy" ],
[ "plant","big","oak tree" ],
[ "element","silicon" ],
[ "element", "dense","uranium" ],
[ "element","light","helium" ],
[ "state","Ohio" ],
[ "state","tiny","Rhode Island" ]
]

# Step 2: assemble data into hash tree

tree = {}

array.each do |record|
node = tree
record.each do |field|
node[field] = {} unless node[field]
node = node[field]
end
end

# Step 3: define recursive display function

def showTree(tab,node)
ts = "\t" * tab
node.keys.sort.each do |key|
puts "#{ts}#{key}"
showTree((tab+1),node[key])
end
end

# Step 4: display the tree

showTree(0,tree)

-----------------------------------------

Output:

animal
bear
fish
big
whale shark
shark
trout
moose
small
squirrel
element
dense
uranium
light
helium
silicon
plant
big
oak tree
cactus
corn
daisy
state
Ohio
tiny
Rhode Island

--
Paul Lutus
http://www.ara...

x1

10/31/2006 3:08:00 AM

0

Jesus! Give me an hour or so to make sense of this. I'm so glad you
provided this!! A++++++++++++

On 10/30/06, Phrogz <gavin@refinery.com> wrote:
> x1 wrote:
> > Team:
> > I'm looking for a pragmatic way of creating a tree from a list of
> > items without knowing the depth of each.
>
> How about this:
> class Hash
> def as_tree( depth=0 )
> map{ |k,subtree|
> me = " "*depth + "#{k} (#{subtree.length})"
> if subtree.empty?
> me
> else
> [ me, subtree.as_tree( depth+1 ) ]
> end
> }.flatten.join( "\n" )
> end
> end
>
> hash_of_hashes = lambda { Hash.new {|h,k| h[k] = hash_of_hashes.call} }
> item_tree = hash_of_hashes.call
>
> items = [ "CarRedFast", "CarGreenSlow", "Car",
> "CarRedFastAgileSadCheeseBurger", "CarRedFastAgileHappyJoy",
> "GreenApplePie", "GreenApple" ]
> items.each do |item|
> current = item_tree
> item.scan( /[A-Z][a-z]+/ ).each{ |piece|
> current = current[ piece ]
> }
> end
>
> puts item_tree.as_tree
> #=> Green (1)
> #=> Apple (1)
> #=> Pie (0)
> #=> Car (2)
> #=> Red (1)
> #=> Fast (1)
> #=> Agile (2)
> #=> Sad (1)
> #=> Cheese (1)
> #=> Burger (0)
> #=> Happy (1)
> #=> Joy (0)
> #=> Green (1)
> #=> Slow (0)
>
>
>

x1

10/31/2006 3:50:00 AM

0

Ok --

Phrogz, I find your script very interesting and I'll learn a lot by
going through it over and over. Thank you!

Paul, Sorry for the crappy data (it just happened to be what I was
working w/ at the time)

One of the key items both of you two used which I was not aware of
(and am ignorant for this) is the ability to use:
current = item_tree #Phrogz
node = tree # Paul

So what this is doing, is creating a new hash at the new depth,
without having to statically reference it. Nice. Yes, I'm a newb to
OO.

Thanks guys

On 10/30/06, x1 <caldridge@gmail.com> wrote:
> Jesus! Give me an hour or so to make sense of this. I'm so glad you
> provided this!! A++++++++++++
>
> On 10/30/06, Phrogz <gavin@refinery.com> wrote:
> > x1 wrote:
> > > Team:
> > > I'm looking for a pragmatic way of creating a tree from a list of
> > > items without knowing the depth of each.
> >
> > How about this:
> > class Hash
> > def as_tree( depth=0 )
> > map{ |k,subtree|
> > me = " "*depth + "#{k} (#{subtree.length})"
> > if subtree.empty?
> > me
> > else
> > [ me, subtree.as_tree( depth+1 ) ]
> > end
> > }.flatten.join( "\n" )
> > end
> > end
> >
> > hash_of_hashes = lambda { Hash.new {|h,k| h[k] = hash_of_hashes.call} }
> > item_tree = hash_of_hashes.call
> >
> > items = [ "CarRedFast", "CarGreenSlow", "Car",
> > "CarRedFastAgileSadCheeseBurger", "CarRedFastAgileHappyJoy",
> > "GreenApplePie", "GreenApple" ]
> > items.each do |item|
> > current = item_tree
> > item.scan( /[A-Z][a-z]+/ ).each{ |piece|
> > current = current[ piece ]
> > }
> > end
> >
> > puts item_tree.as_tree
> > #=> Green (1)
> > #=> Apple (1)
> > #=> Pie (0)
> > #=> Car (2)
> > #=> Red (1)
> > #=> Fast (1)
> > #=> Agile (2)
> > #=> Sad (1)
> > #=> Cheese (1)
> > #=> Burger (0)
> > #=> Happy (1)
> > #=> Joy (0)
> > #=> Green (1)
> > #=> Slow (0)
> >
> >
> >
>
>

Gavin Kistner

10/31/2006 4:48:00 AM

0

Paul Lutus wrote:
> array.each do |record|
> node = tree
> record.each do |field|
> node[field] = {} unless node[field]
> node = node[field]
> end
> end

I like Paul's simple solution better than my
tricky-but-almost-obfuscated autovivifying Hash. One note (that I don't
think is golfing): the innermost code in the above can be rubyified as:
node[field] ||= {}
node = node[field]
or simplified further (golfed?) to:
node = ( node[field] ||= {} )

poopdeville

10/31/2006 9:30:00 PM

0

x1 wrote:
> Team:
> I'm looking for a pragmatic way of creating a tree from a list of
> items without knowing the depth of each.
>

Here's a good algorithm for constructing a formal concept lattice.
http://lanl.arxiv.org/pdf/cs....

It's not particularly pragmatic, but it's fast and ultimately
equivalent to what you're trying to do.

'cid 'ooh

William Black

11/21/2008 12:29:00 PM

0


"James Hogg" <Jas.HoggOUT@SPAM.gmail.com> wrote in message
news:3v8di495g8h0r9ov33qp85ba8nf7fs2gk1@4ax.com...
> On Fri, 21 Nov 2008 11:59:51 -0000, "William Black"
> <william.black@hotmail.co.uk> wrote:
>
>>
>>"J Antero" <ae@re.com> wrote in message
>>> ( A pub piffle reply from Black the pink Zionist Trotskyest red. )
>>
>>Another one who can't manage a conversation without flinging insults.
>
> Look at it as a satirical allusion, an amalgam of
> various insults borrowed from the Housing Officer,
> even down to the missspelling of Trotskyest.

I think you misunderestimate the intelligence of the poster.

It's the spelling in the Micro$oft dictionary.

And yes, I know it's wrong as well...

--
William Black

I've seen things you people wouldn't believe.
Barbeques on fire by the chalets past the castle headland
I watched the gift shops glitter in the darkness off the Newborough gate
All these moments will be lost in time, like icecream on the beach
Time for tea.



Renia

11/21/2008 2:14:00 PM

0

William Black wrote:
> "J Antero" <ae@re.com> wrote in message
> news:wKydnQWfl8EzY7jUnZ2dnUVZ_j2dnZ2d@earthlink.com...
>> "William Black" <william.black@hotmail.co.uk> wrote in message
>> news:gg4e7p$6ju$1@news.motzarella.org...
>>> <temp6@tiglath.net> wrote in message
>>> news:b894d5f3-c8e4-4cd7-8e92-f50df0ac2347@j32g2000yqn.googlegroups.com...
>>>
>>>
>>> There are MANY non-religious Israelis. What's in Israel for them?
>>>
>>> ------------------
>>>
>>> Nobody's going to gas them and cremate the bodies and then pretend they
>>> didn't do it.
>> ( A pub piffle reply from Black the pink Zionist Trotskyest red. )
>
> Another one who can't manage a conversation without flinging insults.

Just like you.

Tiglath

11/21/2008 2:54:00 PM

0

On Nov 20, 7:05 pm, "William Black" <william.bl...@hotmail.co.uk>
wrote:
> <te...@tiglath.net> wrote in message
>
> news:63ec443d-23c3-4d75-ae0a-15bd7a650010@l14g2000yqj.googlegroups.com...
>
> Little Willie veers off course at the first turn.
>
> -------------------
>
> Oh well.
>
> I tried to be civil.
>
> I tried to have a discussion with the arsehole.
>
> You can piss off now Spaniard.
>


I don't care about your civility. Try to be right just for once,
ignorant kike.



Tiglath

11/21/2008 3:27:00 PM

0

On Nov 21, 7:09 am, James Hogg <Jas.Hogg...@SPAM.gmail.com> wrote:
> On Fri, 21 Nov 2008 11:59:51 -0000, "William Black"
>
> <william.bl...@hotmail.co.uk> wrote:
>
> >"J Antero" <a...@re.com> wrote in message
> >> ( A pub piffle reply from Black the pink Zionist Trotskyest red. )
>
> >Another one who can't manage a conversation without flinging insults.
>

Little Willie fakes indignation when caught making a stupid argument.

Here is Little Willie's stupid argument:

Jews should live in Israel and not in England or America for safety
reasons, apparently.

So that no one will perform genocide on them.

Great argument.

Someone tell Little Willie one word: Intifada.

The 1987 Intifada killed some 160 Israelis. The 2000 Intifada more
than 1000. Never mind raining rockets.

Some safety. Little Willie just can't appreciate that he is NOT under
similar risks in the U.K.

Little Willie should travel to Israel and see for himself. Tour buses
carry armed soldiers so that tourists may have some sense of
security. You don't have to scratch very deep to hear Israelis
complain bitterly about the permanence, albeit muffled, war footing
they live in. It's not a relaxing DEFCON.

An engineer lamented that in his weekend military service he had to
deal with Arab children throwing stones at him; he said he no longer
had a taste for it; he had a little child himself and found it very
difficult to shoo other peoples' children at gunpoint.

Little Willie's inane argument is not the first inane argument we've
seen from him, far from, and in typical fashion when called on it he
loses it.

Communists continue to fight intellect, even their own...