Hash order bug?

C

Charles Hoffman

I think this is just a common mistake among newbie-ish programmers.
Which isn't to say anything about Javier specifically, I don't know him,
but in general, a review of one's Data Structures course may be in order
when this happens. But I think it happens to just about every
programmer at some point. I remember the first time I tried to do some
ASP scripting for some web pages and I decided to use the Dictionary
object. At one point I wanted to loop through the Dictionary and
display a listing of its contents. I got all pissed off when I realized
that the loop didn't return the items in alphabetical order. Only later
did I realize that the underlying data structure is a hash, and that the
whole point of a hash is to maximize speed of access by sacrificing
things like, being able to iterate it in any particular order. Of
course, the word "Dictionary" does, for most of us, bring to mind
something that's in alphabetical order, so maybe it was Microsoft's
fault for givig it a dumb name. At any rate, it would be a bad idea to
allow what is essentially a mistake made by programmers to force an
abnormal, slower implementation onto a data structure whose definition
is largely agreed upon in computing. In other words, I'm with the "we
don't need an 'ordered hash'" crowd. I think that, besides slowing it
down, it goes against the very definition of what a hash is.

If you need to iterate through a hash in order by key, it's a simple
matter to grab an array of the keys first, sort it, then iterate from
that. I'm probably going to embarrass myself with my Ruby nuby-ness
here, but off the top of my head:

my_hash.keys.sort.each{|key| doSomethingWith(my_hash[key])}

If you want, and if you really must do away with the overhead of having
to retrieve the key array and sort it first, you could modify the Hash
class with in your own program (Ruby lets you do stuff like that) and
have it keep a sorted array of keys, by adding each new key to it in a
sorted position, after every time an item is added to the hash, and
splicing the key out of the array whenever an item is removed. Then you
could override the each method, and the inspect method if necessary.

--ch--
 
C

Charles Hoffman

If you want, and if you really must do away with the overhead of
having
to retrieve the key array and sort it first,

Mind you, you'd just be amortizing that overhead into each hash
insertion/removal, and paying high interest besides -- to say nothing of
having to write more code ;)

--ch--
 
W

William James

Charles said:
I think this is just a common mistake among newbie-ish programmers.
Which isn't to say anything about Javier specifically, I don't know him,
but in general, a review of one's Data Structures course may be in order
when this happens. But I think it happens to just about every
programmer at some point. I remember the first time I tried to do some
ASP scripting for some web pages and I decided to use the Dictionary
object. At one point I wanted to loop through the Dictionary and
display a listing of its contents. I got all pissed off when I realized
that the loop didn't return the items in alphabetical order. Only later
did I realize that the underlying data structure is a hash, and that the
whole point of a hash is to maximize speed of access by sacrificing
things like, being able to iterate it in any particular order. Of
course, the word "Dictionary" does, for most of us, bring to mind
something that's in alphabetical order, so maybe it was Microsoft's
fault for givig it a dumb name. At any rate, it would be a bad idea to
allow what is essentially a mistake made by programmers to force an
abnormal, slower implementation onto a data structure whose definition
is largely agreed upon in computing. In other words, I'm with the "we
don't need an 'ordered hash'" crowd. I think that, besides slowing it
down, it goes against the very definition of what a hash is.
True.


If you need to iterate through a hash in order by key, it's a simple
matter to grab an array of the keys first, sort it, then iterate from
that. I'm probably going to embarrass myself with my Ruby nuby-ness
here, but off the top of my head:

my_hash.keys.sort.each{|key| doSomethingWith(my_hash[key])}

h = { 'zebra', 2, 'horse', 0, 'sheep', 1 }
==>{"horse"=>0, "sheep"=>1, "zebra"=>2}
h.sort.each{|x| p x}
["horse", 0]
["sheep", 1]
["zebra", 2]
==>[["horse", 0], ["sheep", 1], ["zebra", 2]]
 
C

Chad Perrin

Which isn't to say anything about Javier specifically, I don't know him,
but in general, a review of one's Data Structures course may be in order
when this happens. But I think it happens to just about every
programmer at some point.

Oddly enough, I never made that assumption -- but I think that's because
I first learned about hashes/dictionaries/associative arrays by reading
something that explained up-front the fact that they're not ordered and,
more to the point, why they aren't ordered, in any particular manner
that makes immediate sense to the programmer.

course, the word "Dictionary" does, for most of us, bring to mind
something that's in alphabetical order, so maybe it was Microsoft's
fault for givig it a dumb name.

If so, you might want to have some words with Guido van Rossum about the
use of the term "dictionary" in Python. I'd probably be happier with
"lexicon" than "dictionary", but I like "hash" most of all.
"Associative array" is probably best, aside from the fact that it's WAY
too long to be comfortable for general use.

is largely agreed upon in computing. In other words, I'm with the "we
don't need an 'ordered hash'" crowd. I think that, besides slowing it
down, it goes against the very definition of what a hash is.

Agreed . . . but I wouldn't be opposed to a method that produces
alphabetized and/or asciibetized output, by key, from a hash.
 
J

Just Another Victim of the Ambient Morality

Why doesn't someone write a red-black tree for Ruby? I mean, it would
be trivial to do with a C++ extension and std::map<>...
 
H

Hal Fulton

Just said:
Why doesn't someone write a red-black tree for Ruby? I mean, it would
be trivial to do with a C++ extension and std::map<>...


Not sure, but I think it's been done.

Hal
 
C

Charles Hoffman

If so, you might want to have some words with Guido van Rossum about the
use of the term "dictionary" in Python. I'd probably be happier with
"lexicon" than "dictionary", but I like "hash" most of all.
"Associative array" is probably best, aside from the fact that it's WAY
too long to be comfortable for general use.

I like "Hash" because it reminds you opf the fact that its
implementation involves "hashing" they keys with a mathematical function
of some sort so as to make them quick to get to.

I didn't know Python calls it Dictionary too. I don't know any Python
actually.
Agreed . . . but I wouldn't be opposed to a method that produces
alphabetized and/or asciibetized output, by key, from a hash.

I think someone posted in this thread an example showing that Hash has a
sort method. But now I'm not so sure...

/me heads off to irb to try it...

--ch--
 
C

Charles Hoffman

I think someone posted in this thread an example showing that Hash has a
sort method. But now I'm not so sure...

/me heads off to irb to try it...

irb(main):001:0> h = { 'horse' => 5, 'pig' => 7, 'car' => 12, 'five' =>
3 }
=> {"five"=>3, "horse"=>5, "pig"=>7, "car"=>12}
irb(main):002:0> h
=> {"five"=>3, "horse"=>5, "pig"=>7, "car"=>12}
irb(main):003:0> h.sort
=> [["car", 12], ["five", 3], ["horse", 5], ["pig", 7]]

Sure enough... returns an nX2 array whose rows are key, value, and
sorted by key.

Doesn't work when your keys are symbols, though:

irb(main):006:0> h = { :horse => 5, :pig => 7, :car => 12, :five => 3 }
=> {:car=>12, :five=>3, :horse=>5, :pig=>7}
irb(main):007:0> h.sort
NoMethodError: undefined method `<=>' for :car:Symbol
from (irb):7:in `<=>'
from (irb):7
from :0
irb(main):008:0>

So long as the types of the keys all suuport the spaceship operator,
however, it looks like hashes will sort.

--ch--
 
C

Chad Perrin

irb(main):003:0> h.sort
=> [["car", 12], ["five", 3], ["horse", 5], ["pig", 7]]

Sure enough... returns an nX2 array whose rows are key, value, and
sorted by key.

Doesn't work when your keys are symbols, though:

That would explain why I thought .sort didn't work with hashes.
 
L

Logan Capaldo

irb(main):003:0> h.sort
=> [["car", 12], ["five", 3], ["horse", 5], ["pig", 7]]

Sure enough... returns an nX2 array whose rows are key, value, and
sorted by key.

Doesn't work when your keys are symbols, though:

That would explain why I thought .sort didn't work with hashes.

hash.sort_by{ |k,v| k.to_s }

 
C

Charles Hoffman

hash.sort_by{ |k,v| k.to_s }

Alternately, you could implement a <=> method for symbols that converts
to strings... something like

class Symbol
def <=>(other)
self.to_s <=> other.to_s
end
end

That might come in handy for other things... maybe not. If it even
works, being just off the top of my head and all.

--ch--
 
C

Charles Hoffman

That might come in handy for other things... maybe not. If it even
works, being just off the top of my head and all.

Hey, it does. Man, I'm really starting to like this Ruby stuff. Now I
just have to come up with a good project so I have an excuse to code in
it for real ;)

--ch--
 
D

dblack

Hi --

Hi, I missed some of this thread, I only just joined the list. Although it's
less than optimal, can you not just sort the keys when you need them.
Something like:

require 'enumerator'
sorted_keys = hash.enum_for:)each_key).to_a.sort

Again, there might very well be a better way to do even that, I'm new to
ruby.


sorted_keys = hash.keys.sort

:)


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
J

John Joyce

Hi

Well, that certainly is easier. Coming from other programming
languages
(which I won't name), I expect the answer to be more tricky than it
is. I'm
learning something new every day

Thanks,
Nick

Ruby is often this way. If it seems like the thing you want to do
isn't working, and you are thinking of it in another programming
language, then it is probably easier in Ruby. (generally)
 
R

Robert Dober

Hi --




sorted_keys = hash.keys.sort
sorted_keys = hash.keys.sort_by{|k| k.to_s }
as pointed out already.


As an aside:
Will symbols be comparable in Ruby2? Am I off to yet another RCR, nooo!!!


But as another remark ordered Hashes do not necessarily mean "order by
keys" or "order by values" sometimes you want them ordered by
chronological order where
the hash literal assignment
hsh= {:a=>42, :b=>1764} would be equivalent ro
hsh={}
hsh[:a]=42
hsh[:b]=42*42
of course.


Cheers
Robert
 
D

David A. Black

Hi --

sorted_keys = hash.keys.sort_by{|k| k.to_s }
as pointed out already.

I can't seem to find the first two or three messages in this thread
anywhere (including Google groups), so I may have missed something.
Are only talking about strings and symbols as keys? If so I won't
bother pointing out that to_s won't work with integers :)


David

--
Upcoming Rails training by Ruby Power and Light:
Four-day Intro to Intermediate
May 8-11, 2007
Edison, NJ
http://www.rubypal.com/events/05082007
 
R

Robert Dober

Hi --



I can't seem to find the first two or three messages in this thread
anywhere (including Google groups), so I may have missed something.
Are only talking about strings and symbols as keys? If so I won't
bother pointing out that to_s won't work with integers :)

Hi David,

unfortunately Symbols are *not* comparable :( (yet)
516/17 > irb
irb(main):001:0> :a < :b
NoMethodError: undefined method `<' for :a:Symbol
from (irb):1

that is why I talked about a potential RCR.

Cheers
Robert
 
D

David A. Black

Hi --

Hi David,

unfortunately Symbols are *not* comparable :( (yet)
516/17 > irb
irb(main):001:0> :a < :b
NoMethodError: undefined method `<' for :a:Symbol
from (irb):1

that is why I talked about a potential RCR.

Right -- what I mean is, to_s is OK for strings and symbols but not
for integers.


David

--
Upcoming Rails training by Ruby Power and Light:
Four-day Intro to Intermediate
May 8-11, 2007
Edison, NJ
http://www.rubypal.com/events/05082007
 

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
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top