PGH : Pretty Good Hash v0.1

V

VK

Any use for this?

And yes, once again: HASH is NOT an ARRAY!

function Hash() {
this.$_data = new Object();

this.add = function(k,v) {
if (k!=null) {
this.$_data[k] = v;
}
}

this.remove = function(k) {
if (k!=null) {
delete(this.$_data[k]);
}
}

this.length = function() {
var i = 0;
for (prop in this.$_data){
i++;}
return i;};

this.keys = function() {
var a = new Array();
for (prop in this.$_data){a.push(prop);}
return a;};

this.values = function() {
var a = new Array();
for (prop in this.$_data){a.push(this.$_data[prop]);}
return a;};
}

var myHash = new Hash();
// fill the hash with key/value pairs:
myHash.add('c','v3'); myHash.add('a','v1'); myHash.add('b','v2');
// get hash length:
alert(myHash.length());
// get sorted keys:
alert(myHash.keys().sort());
// get unsorted values:
alert(myHash.values());
// remove a key/value pair by key:
myHash.remove('a');
 
V

VK

Ha-ha-ha, stupid me :-(
Would be nice to get partucular values too, I guess...

....
this.getValue = function(k) {
if (k!=null) {
return this.$_data[k];
}
....
 
J

Jim Ley

this.length = function() {
var i = 0;
for (prop in this.$_data){
i++;}
return i;};

for a in x suffers from a couple of problems, the important one being
enumerating the prototypes, but also it's incredibly slow.

Since you can only add by using .add it's silly to not create the keys
etc. on creation.

Jim.
 
M

Martin Honnen

VK wrote:

function Hash() {
this.$_data = new Object();

this.add = function(k,v) {


You should move the methods out to the prototype e.g.
Hash.prototype.add = function ...
as that way they are shared by all instances created with new Hash().
 
M

Michael Winter

[snip]
function Hash() {
this.$_data = new Object();

As this is private data it would be better as a local variable to the Hash
constructor rather than an object member. See
<URL:http://www.crockford.com/javascript/private.html>.

[snip]
this.length = function() {
var i = 0;
for (prop in this.$_data){
i++;}
return i;};

I don't like the idea of enumerating an object. What if an implementation
has enumerable properties on "plain" objects? In any case, it's much
better to keep track of the number of elements yourself. For one thing,
it's much quicker.

Take a look at <URL:http://www.mlwinter.pwp.blueyonder.co.uk/clj/hash.js>.

By the way, are you aware that you've provided no direct method of
retrieving an element by key?

[snip]

Mike
 
R

Robert

VK wrote:
....
this.getValue = function(k) {
if (k!=null) {
return this.$_data[k];
}

You can use propertyIsEnumerable() to weed out predefined objects.
Robert
 
M

Michael Winter

[snip]
You can use propertyIsEnumerable() to weed out predefined objects.

Whilst all non-enumerable properties are predefined, it doesn't
necessarily follow that all predefined properties are non-enumerable.

The best thing to do is avoid the situation altogether, particularly as
that method is only defined in more recent browsers.

Mike
 
C

codeHanger

Michael said:
[snip]
You can use propertyIsEnumerable() to weed out predefined objects.

Whilst all non-enumerable properties are predefined, it doesn't
necessarily follow that all predefined properties are non-enumerable.

The best thing to do is avoid the situation altogether, particularly as
that method is only defined in more recent browsers.

Another approach would be to use "hasOwnProperty". Of course it's not
available in older browsers either, but it doesn't seem that it would
be that difficult to conditionally add through prototype for those that
are deficient in this regard.

It should then be quite straightforward to create a Hashtable emulation
using JS objects, one that doesn't suffer any interference from
pre-defined values in those objects.

And, as a further thought/wish, if getters/setters were universally
available, it should be possible to use JS syntax directly for get/put
operations. :)

Regards,

../rh
 
M

Michael Winter

[snip]
Another approach would be to use "hasOwnProperty". Of course it's not
available in older browsers either, but it doesn't seem that it would be
that difficult to conditionally add through prototype for those that are
deficient in this regard.

True, but then enumeration (if required) would be wholly inefficient. I
prefer Richard Cornford's approach (which I used, too).

[snip]

Mike
 
C

codeHanger

Michael said:
[snip]
Another approach would be to use "hasOwnProperty". Of course it's not
available in older browsers either, but it doesn't seem that it would be
that difficult to conditionally add through prototype for those that are
deficient in this regard.

True, but then enumeration (if required) would be wholly inefficient. I
prefer Richard Cornford's approach (which I used, too).

Well, Mike, you're entitled to choose your horse based on the jockey --
Richard's approach is unfailingly good, and he's always an excellent
bet.

However, for all I know "hasOwnProperty" may not have been in the race,
i.e, in existence or considered, at the time he worked on this.

Whether enumeration would be wholly inefficient under a non-linked-list
approach would depend on what is done to accomodate the requirement.

Just as special measures are used to ensure lookup in a link-list are
efficient, so could steps be taken to ensure enumeration would be
efficient in the alternate approach (e.g., by updating the enumeration
as put/removes are performed on the hashtable).
Regards,

.../rh
 
M

Michael Winter

[snip]
Well, Mike, you're entitled to choose your horse based on the jockey

I don't prefer Richard's just because it's Richard's. I think that the
data structure it centres around is good for a generic implementation. I
didn't concur with every decision he made, which is why the implementation
I wrote differs in some regards, even if they are relatively insignificant.

I imagine that the basic get/put/remove operations would be faster using
the hasOwnProperty method and if that's where speed really matters in a
particular situation, it might be the best approach regardless of other
issues.

[snip]
However, for all I know "hasOwnProperty" may not have been in the race,
i.e, in existence or considered, at the time he worked on this.

That is quite possible. Only one person could say for certain. :)
Whether enumeration would be wholly inefficient under a non-linked-list
approach would depend on what is done to accomodate the requirement.

If you're willing to produce an alternative, I'd be interested to see it.
Of course, any meaningful performance comparison would require that both
approaches provide the same functionality.

[snip]

Mike
 
C

codeHanger

Michael said:
[snip]
Well, Mike, you're entitled to choose your horse based on the
jockey

I don't prefer Richard's just because it's Richard's. I think that the
data structure it centres around is good for a generic implementation. I
didn't concur with every decision he made, which is why the implementation
I wrote differs in some regards, even if they are relatively insignificant.

I apologize if the remark was found to be a bit too cutting (the spirit
of the season should overcome me soon ;-)). If so, it belies the fact
that I hold your work in very high regard, and am continually amazed at
the volume produced, and the point-on accuracy of your responses.
I imagine that the basic get/put/remove operations would be faster using
the hasOwnProperty method and if that's where speed really matters in a
particular situation, it might be the best approach regardless of other
issues.

I believe the volume of code, along with complexity, would be reduced
by quite a bit as well, which is also important.

If you're willing to produce an alternative, I'd be interested to see it.
Of course, any meaningful performance comparison would require that both
approaches provide the same functionality.

I have a start on it -- I'll see if I can find time to put it in shape
for posting.

Regards,

... Ron
 
R

Richard Cornford

Michael said:
<[email protected]> wrote:

That is quite possible. Only one person could say for
certain. :)
<snip>

The very first version of my enumerating hash table was required to work
with Netscape 4 so - hasOwnProperty - was not considered. I have not
seen any reason to re-consider that aspect of my strategy in later
versions, though I am interested in seeing - hasOwnProperty - tested in
comparison.

In the event that we see a - hasOwnProperty - implementations it might
be interesting to also see the testing script used for comparison, so
that other variations could be tried out with it. We might end up with
something objectively optimal, speed and code-size wise.

Richard.
 
C

codeHanger

If you're willing to produce an alternative, I'd be interested to see it.
Of course, any meaningful performance comparison would require that both
approaches provide the same functionality.

OK, here's an alternative. After all the ballyhoo, you'll probably note
that it doesn't use "hasOwnProperty". So why not?

Well, it did to start with. I created a "hasOwnProperty" prototype to
cover off browsers that don't have that feature built-in. Then I
realized I would also have to use "apply" in the single case where
"hasOwnProperty" was a key within the hash. That was fine, too, since
apply is also relatively easy to prototype. And then I did some timing
tests, which showed it performed very well.

That was until Opera was tried, and performance turned out to be
absolutely dismal. "hasOwnProperty" performance in Opera appeared to be
at the root of the problem.

So, this.containsKey is now a very quick whack-attack at providing
performance in Opera, as well as the other browsers that were tested
(IE, Firefox, Mozilla, Netscape). While I think it's reliable within
the known pre-defined values, it shouldn't be difficult ensure the
reliability with something just slightly more innovative.

As you suggested/requested, I believe equivalent functionality should
be there. I haven't tried to do everything to the letter, e.g.,
iterator behaviour under concurrent hash changes will be different, and
undefined values are currently allowed.

My testing was concentrated on performance, and only very rudimentary
testing was done on the basic functionality. So I'm sure you'll
encounter some things that aren't quite right. On the positive side,
problems shouldn't be hard to fix, given the straightforward nature of
the implementation.

There's possibly room for further performance improvement -- e.g., I
didn't embed information in the keys (as I believe you/Richard did).

Regards,

.../rh

(ggroups will of course undo the formatting):

function Hashtable( ) {
var hash = { } ;
var hashEnum = [ ];
var size = 0, hashChangeId = 0;

this.get = function( key ) {
if ( this.containsKey( key ) ) return hash[ key ] [ 0 ];
}

this.put = function( key, value ) {
if ( ! key ) return false;
var pos = this.containsKey( key ) ? hash[key][1] :
hashEnum.length;
hash[ key ] = [ value, pos ];
size++, hashChangeId++;
hashEnum[ pos ] = key;
return true;
}

this.remove = function( key ) {
if ( ! this.containsKey( key ) ) return false;
size--, hashChangeId++;
delete hashEnum[ hash[ key ] [ 1 ] ];
delete hash[ key ];
return true;
}

this.clear = function( ) {
hash = { } ;
hashEnum.length = size = 0, hashChangeId++;
}

this.keys = function( ) {
return new Enumerator( );
}

this.values = function( ) {
return new Enumerator( true );
}

this.containsKey = function( key ) {
var val = hash[key];
if (val && ! isNaN(val[1])
&& hashEnum[val[1]] == key) return true;
return false;
}

this.size = function( ) {
return size;
}

/******************************************************************************/
function Enumerator( values ) {
var nextIndex = 0;
var id = hashChangeId;
var which = values;

this.next = function( ) {
if ( this.hasNext( ) ) return which ? hash[hashEnum[
nextIndex++ ]] [ 0 ] : hashEnum[ nextIndex++ ];
}
this.hasNext = function( ) {
if ( id != hashChangeId ) return false;
while ( ! hashEnum[ nextIndex ] && nextIndex <=
hashEnum.length ) nextIndex++;
return nextIndex < hashEnum.length;
}
}
}
/******************************************************************************/
Hashtable.prototype.toString = function( ) {
var keys = this.keys( ) , str = [ ];
while ( keys.hasNext( ) ) key = keys.next( ) , str[ str.length ] =
key + " : " + this.get( key );
return "{"+str.join( ", " ) + "}";
}

/******************************************************************************/
Hashtable.prototype.clone = function( ) {
var keys = this.keys( ) , clone = new Hashtable;
while ( keys.hasNext( ) ) key = keys.next( ) , clone.put( key,
this.get( key ) );
return clone;
}

/******************************************************************************/
Hashtable.prototype.containsValue = function( value ) {
var values = this.values( );
while ( values.hasNext( ) ) if (value === values.next( ))
return true;
return false;

}
/******************************************************************************/
Hashtable.prototype.isEmpty = function( ) {
return ! this.size( );
}
 
C

codeHanger

Dr said:
JRS: In article
dated Thu, 23 Dec 2004 22:54:37, seen in (e-mail address removed) posted :

Then don't use it. Or start every line with "/**/ ".

John, I was just doing the preparation for our Christmas Eve dinner,
and as I was stuffing the turkey, I was thinking of you ... [ a bit
of borrowed humour there, but I was in fact stuffing the turkey, and I
do try not to think of you :)].

Actually, the line prefix suggestion is a good one -- I'll keep it in
mind if I feel the urge to post code again, and should Google not be
able to get it together in the meantime.
/**/
/**/ Merry Christmas,
/**/
../rh
 
C

codeHanger

Dr said:
JRS: In article
dated Thu, 23 Dec 2004 22:54:37, seen in (e-mail address removed) posted :

Then don't use it. Or start every line with "/**/ ".

John, I was just doing the preparation for our Christmas Eve dinner,
and as I was stuffing the turkey, I was thinking of you ... [ a bit
of borrowed humour there, but I was in fact stuffing the turkey, and I
do try not to think of you :)].

Actually, the line prefix suggestion is a good one -- I'll keep it in
mind if I feel the urge to post code again, and should Google not be
able to get it together in the meantime.
/**/
/**/ Merry Christmas,
/**/
../rh
 

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

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top