Connecting Tech Pros Worldwide Help | Site Map

Problem with for/in loop over associative array

  #1  
Old July 23rd, 2005, 08:15 PM
Yereth Jansen
Guest
 
Posts: n/a
Hi all,

I encountered a problem with looping through an associative array. All
worked perfectly with the following code:

for (var menuItem in this.menuItems) {
doSomething();
}

where this.menuItems is an associative array. The problem occurred when
I added the following function to the Array prototype:

Array.prototype.print_r = function() {
print_the_array_code();
}

After adding this method, the for/in loop took print_r as an element as
well. So besides the items I actually wanted to get from my array, I
also go print_r, which obviously I don't want. Does anyone have a
suggestion what to do with this..?

Thanks in advance,
Yereth Jansen
  #2  
Old July 23rd, 2005, 08:15 PM
Douglas Crockford
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


> I encountered a problem with looping through an associative array. All[color=blue]
> worked perfectly with the following code:
>
> for (var menuItem in this.menuItems) {
> doSomething();
> }
>
> where this.menuItems is an associative array. The problem occurred when
> I added the following function to the Array prototype:
>
> Array.prototype.print_r = function() {
> print_the_array_code();
> }
>
> After adding this method, the for/in loop took print_r as an element as
> well. So besides the items I actually wanted to get from my array, I
> also go print_r, which obviously I don't want. Does anyone have a
> suggestion what to do with this..?[/color]

Your for should be

for (var i; i < this.menuItems.length; i += 1) {

http://www.crockford.com/javascript/survey.html
  #3  
Old July 23rd, 2005, 08:15 PM
Yereth Jansen
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


Douglas Crockford wrote:[color=blue]
> Your for should be
>
> for (var i; i < this.menuItems.length; i += 1) {
>
> http://www.crockford.com/javascript/survey.html[/color]

That won't work. I am using an associative array as in a hash. An
associative array does not have a numerical index nor does it have the
property .length set like I want it. ".length" is 0 in all cases.
  #4  
Old July 23rd, 2005, 08:15 PM
Douglas Crockford
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


>> Your for should be[color=blue][color=green]
>>
>> for (var i; i < this.menuItems.length; i += 1) {
>>
>> http://www.crockford.com/javascript/survey.html[/color]
>
> That won't work. I am using an associative array as in a hash. An
> associative array does not have a numerical index nor does it have the
> property .length set like I want it. ".length" is 0 in all cases.[/color]

Do not use Array when you do not need .length. You should be using an
Object. It is best to not use the term "associative array" when working
in JavaScript because it will confuse you.

Use the typeof operator on the values you extract, and skip the ones
that are 'function'.

http://www.crockford.com/javascript/survey.html
  #5  
Old July 23rd, 2005, 08:15 PM
Yereth Jansen
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


Douglas Crockford wrote:[color=blue]
> Do not use Array when you do not need .length. You should be using an
> Object. It is best to not use the term "associative array" when working
> in JavaScript because it will confuse you.
>
> Use the typeof operator on the values you extract, and skip the ones
> that are 'function'.
>
> http://www.crockford.com/javascript/survey.html[/color]

Thank you. I was hoping for another answer than this one, but I
suspected it was the only 'solution'. No such luck I guess. Thanks for
helping.

Cheers.
  #6  
Old July 23rd, 2005, 08:15 PM
Michael Winter
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


On 18/04/2005 14:24, Yereth Jansen wrote:

[To avoid enumerating user-defined functions]
[color=blue]
> Douglas Crockford wrote:[/color]

[snip]
[color=blue][color=green]
>> Use the typeof operator on the values you extract, and skip the ones
>> that are 'function'.[/color][/color]

[snip]
[color=blue]
> Thank you. I was hoping for another answer than this one, but I
> suspected it was the only 'solution'. No such luck I guess.[/color]

Well, you could use your own hashtable implementation. You'd sacrifice
the ability to use square bracket notation, but you would have
consistent, controlled behaviour. The archives of this newsgroup (via
Google Groups) will have several implementations (including mine :).

Mike

--
Michael Winter
Replace ".invalid" with ".uk" to reply by e-mail.
  #7  
Old July 23rd, 2005, 08:15 PM
John G Harris
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


In article <d40c60$sfj$1@azure.qinip.net>, Yereth Jansen
<yajansen.no@spam.cs.uu.nl> writes[color=blue]
>Douglas Crockford wrote:[color=green]
>> Do not use Array when you do not need .length. You should be using an
>>Object. It is best to not use the term "associative array" when
>>working in JavaScript because it will confuse you.
>> Use the typeof operator on the values you extract, and skip the ones
>>that are 'function'.
>> http://www.crockford.com/javascript/survey.html[/color]
>
>Thank you. I was hoping for another answer than this one, but I
>suspected it was the only 'solution'. No such luck I guess. Thanks for
>helping.[/color]

It's worth saying again : if you say "associative array" you are likely
to forget that they are objects with properties, and that a method is
just a property whose value happens to be a function object.

Also, it might not occur to you to build a prototype object to keep all
the methods out of the way.

John
--
John Harris
  #8  
Old July 23rd, 2005, 08:16 PM
Csaba Gabor
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


Yereth Jansen wrote:[color=blue]
> All worked perfectly with the following code:
>
> for (var menuItem in this.menuItems) {
> doSomething();
> }
>
> where this.menuItems is an associative array. The problem occurred when
> I added the following function to the Array prototype:
>
> Array.prototype.print_r = function() {
> print_the_array_code();
> }[/color]

It's not exactly clear what you want (ie. on what basis you wish the
print_r to be filtered), but perhaps this quickly-thrown-together
function comes close to what you are looking for:

function showNonPrototypes(obj) {
var oForbidden = {}; // list of keys on the prototype chain
var prType = ""; // the prototype type
var idx;
if (typeof(obj)=="object") {
var objType = ""+obj; // looking for [object prType]
if ((obj.length + "")!="undefined") prType = "Array";
else if (objType.substring(0,7)=="object ")
prType = objType.substring(7);
if (prType && window[prType] && window[prType].prototype)
for (idx in window[prType].prototype) oForbidden[idx] = 1;
for (idx in obj)
if (!oForbidden[idx])
alert(idx); // doSomething();
}
}

// Example
Object.prototype.print_r = function () { return "nice array code"; };
var aTest = []; // starts life as an array
aTest.x = "y";
aTest[2] = 45;
aTest.z = "borf";
showNonPrototypes(aTest);


Csaba Gabor from Vienna
  #9  
Old July 23rd, 2005, 08:17 PM
rh
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


Csaba Gabor wrote:[color=blue]
> Yereth Jansen wrote:[color=green]
> > All worked perfectly with the following code:
> >
> > for (var menuItem in this.menuItems) {
> > doSomething();
> > }
> >
> > where this.menuItems is an associative array. The problem occurred[/color][/color]
when[color=blue][color=green]
> > I added the following function to the Array prototype:
> >
> > Array.prototype.print_r = function() {
> > print_the_array_code();
> > }[/color]
>
> It's not exactly clear what you want (ie. on what basis you wish the
> print_r to be filtered), but perhaps this quickly-thrown-together
> function comes close to what you are looking for:
>
> function showNonPrototypes(obj) {
> var oForbidden = {}; // list of keys on the prototype chain
> var prType = ""; // the prototype type
> var idx;
> if (typeof(obj)=="object") {
> var objType = ""+obj; // looking for [object prType]
> if ((obj.length + "")!="undefined") prType = "Array";
> else if (objType.substring(0,7)=="object ")
> prType = objType.substring(7);
> if (prType && window[prType] && window[prType].prototype)
> for (idx in window[prType].prototype) oForbidden[idx] =[/color]
1;[color=blue]
> for (idx in obj)
> if (!oForbidden[idx])
> alert(idx); // doSomething();
> }
> }
>
> // Example
> Object.prototype.print_r = function () { return "nice array code"; };
> var aTest = []; // starts life as an array
> aTest.x = "y";
> aTest[2] = 45;
> aTest.z = "borf";
> showNonPrototypes(aTest);
>[/color]

That seems rather obtuse -- it could be much better accomplished by
making use of the "hasOwnProperty" function:

for (var k in aTest) {
if(aTest.hasOwnProperty(k)) {
alert("Has own property "+k + " : "+aTest[k]);
}
}

If there's a concern for older browsers that don't provide this
function, a reasonably good equivalent can be added as:

if (! Object.prototype.hasOwnProperty) {
Object.prototype.hasOwnProperty = function(pty) {
return (typeof this[pty] != "undefined" &&
(this.constructor
&& this.constructor.prototype
&& this.constructor.prototype[pty] !== this[pty]))
}
}

.../rh

  #10  
Old July 23rd, 2005, 08:17 PM
Yereth Jansen
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


Michael Winter wrote:[color=blue]
> Well, you could use your own hashtable implementation. You'd sacrifice
> the ability to use square bracket notation, but you would have
> consistent, controlled behaviour. The archives of this newsgroup (via
> Google Groups) will have several implementations (including mine :).
>
> Mike[/color]


It crossed my mind and I've seen the sample implementations. Not sure if
it was yours, but if I'll use it I'll make sure to credit your work. ;)
Right now I've decided to not define prototype functions for array, but
rather functions that take an array as an argument, like php does it. I
was just a bit too much into OO programming (yes, even with javascript),
so I was quite stubborn in wanting it to be 'native' functions of the
object.

Anyhue, I will go for the external functions for now, until it doesn't
suite me any longer.

Thanks for the help!

Yereth
  #11  
Old July 23rd, 2005, 08:17 PM
Yereth Jansen
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


John G Harris wrote:[color=blue]
> It's worth saying again : if you say "associative array" you are likely
> to forget that they are objects with properties, and that a method is
> just a property whose value happens to be a function object.[/color]

I actually did not realize this before, but before I posted this I've
realized that associative arrays were more of a hack than a native
datastructure in javascript. The tutorials never told me, unfortunately.
Or I just plainly missed it as I was not aware of the possibility.
[color=blue]
> Also, it might not occur to you to build a prototype object to keep all
> the methods out of the way.[/color]

See my other reply on Michael's mail. Customizing is out of the question
for now. Mainly because the necessity is not really there.

Thanks for the help!

Yereth

  #12  
Old July 23rd, 2005, 08:17 PM
Yereth Jansen
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


rh wrote:[color=blue]
> That seems rather obtuse -- it could be much better accomplished by
> making use of the "hasOwnProperty" function:
>
> for (var k in aTest) {
> if(aTest.hasOwnProperty(k)) {
> alert("Has own property "+k + " : "+aTest[k]);
> }
> }
>
> If there's a concern for older browsers that don't provide this
> function, a reasonably good equivalent can be added as:
>
> if (! Object.prototype.hasOwnProperty) {
> Object.prototype.hasOwnProperty = function(pty) {
> return (typeof this[pty] != "undefined" &&
> (this.constructor
> && this.constructor.prototype
> && this.constructor.prototype[pty] !== this[pty]))
> }
> }
>
> ../rh[/color]

There is no concern for older browsers or any other browser that I am
testing with as I am producing a content management system. We set the
demands. :-)

Thanks for the help both Csaba and rh. This will help me to write my
implementation most fit for the job.

Cheers,
Yereth
  #13  
Old July 23rd, 2005, 08:17 PM
Alexis Nikichine
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


John G Harris wrote:[color=blue]
> It's worth saying again : if you say "associative array" you are likely
> to forget that they are objects with properties, and that a method is
> just a property whose value happens to be a function object.
>
> Also, it might not occur to you to build a prototype object to keep all
> the methods out of the way.[/color]

I am afraid I don't understand how building a prototype object will keep
all the methods out of the way. As far as I know, it will keep them out
of the way of the delete operator, but not out of the way of for-in
enumerations, which is the relevant point for the current problem.

Could you please elaborate some further on this ?

Alexis

--
Some domain is free
  #14  
Old July 23rd, 2005, 08:18 PM
rh
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


Yereth Jansen wrote:[color=blue]
> rh wrote:[/color]

<..>
[color=blue][color=green]
> > for (var k in aTest) {
> > if(aTest.hasOwnProperty(k)) {
> > alert("Has own property "+k + " : "+aTest[k]);
> > }
> > }[/color][/color]

<..>
[color=blue]
> There is no concern for older browsers or any other browser that I am[/color]
[color=blue]
> testing with as I am producing a content management system. We set[/color]
the[color=blue]
> demands. :-)
>[/color]

That's fine. One small caution here: There appears to be a bug in Opera
(7.5) with regard to hasOwnProperty when it involves a numeric
(-->string) property name . E.g.,

var x = { "2":true };
alert( x.hasOwnProperty("2") ); // *** false *** under Opera

This turned up when running Csaba's sample test.

../rh

  #15  
Old July 23rd, 2005, 08:18 PM
John G Harris
Guest
 
Posts: n/a

re: Problem with for/in loop over associative array


In article <42662857$0$7210$626a14ce@news.free.fr>, Alexis Nikichine
<alexis.nikichine@somedomain.fr> writes[color=blue]
>John G Harris wrote:[color=green]
>> It's worth saying again : if you say "associative array" you are likely
>> to forget that they are objects with properties, and that a method is
>> just a property whose value happens to be a function object.
>> Also, it might not occur to you to build a prototype object to keep
>>all
>> the methods out of the way.[/color]
>
>I am afraid I don't understand how building a prototype object will
>keep all the methods out of the way. As far as I know, it will keep
>them out of the way of the delete operator, but not out of the way of
>for-in enumerations, which is the relevant point for the current
>problem.
>
>Could you please elaborate some further on this ?[/color]

Only to say you're right : for/in does indeed crawl up the prototype
chain (ECMA 262 v3, sec 12.6.4, last paragraph).

I blame the Mongolian vodka I'd sampled earlier in the day :-)

John
--
John Harris
Closed Thread


Similar Threads
Thread Thread Starter Forum Replies Last Post
The fastest way to fill 2D dynamic array with zeros romayankin@gmail.com answers 14 February 26th, 2006 05:25 AM
clc selected threads (30-jan-2005 to 31-jan-2005) #1 sathyashrayan answers 6 November 14th, 2005 06:51 PM
Alternatives to the C++ Standard Library? Steven T. Hatton answers 43 July 23rd, 2005 06:52 AM
Resorting an array? LRW answers 4 July 17th, 2005 08:59 AM