Order of Key-Value pair ("associative arrays")

A

Abdullah Kauchali

Hi folks,

Can one rely on the order of keys inserted into an associative Javascript
array? For example:


var o = new Object();

o["first"] = "Adam";
o["second"] = "Eve";
o["third"] = "Cane";
o["fourth"] = "Abel";

..
..
..

//then

for (var i in o){
alert(i);
}

Is the order in this "for loop" *guaranteed* to be:
first, second, third, fourth?

Also, if the "third" key is deleted, is the order still guaranteed?

I've tested this in IE and Firefox, and it seems to work. I'd be grateful
for any links that indicate this in Javascript standards/specs.

Many thanks & kind regards,

Abdullah
 
Z

ZER0

On Tue, 25 May 2004 12:35:50 +0200, Abdullah Kauchali wrote:

[cut]
Is the order in this "for loop" *guaranteed* to be:
first, second, third, fourth?

Unfortunately, not.
Depend of the browser's implementation of this aspect of ECMAScript
specifications.

In IE,old Netscape versions, and Gecko based browsers, the order is
"chronological".. But.. try with Opera.
for any links that indicate this in Javascript standards/specs.

http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf

[for-in statement]
"The mechanics of enumerating the properties (..) is
implementation dependent. The order of enumeration is defined by the
object. (..) "

--
ZER0://coder.gfxer.web-designer/

~ Come devo regolare la stampante laser per stordire?
(How do I set a laser printer to stun?)

on air ~ "Linkin Park - Somewhere I Belong (real song)"
 
A

Abdullah Kauchali

ZER0 said:
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf

[for-in statement]
"The mechanics of enumerating the properties (..) is
implementation dependent. The order of enumeration is defined by the
object. (..) "


Ho bummer! :(

Thanks for that Zero.

Now, how do I accomplish the following if the order is not guaranteed:

1. Put objects within the "collection";
2. Access each one according to the order in which they were put into the
collection.

So far, I have this:

It seems to me that the most straight-forward answer would be to create
another "collection" with index numbers beginning with 0 and then always
incrementing for additions to the collections. Once a index/offset number
is used, it cannot be reused.

So, after some additions and deletions, I'll get something like:

1, 2, 3, 7, 9, 11, 23

if I wanted to add to this collection, the next one would be 24 and so on.

Is that the most elegant solution?

Kind regards

Abdullah
 
D

Douglas Crockford

Can one rely on the order of keys inserted into an associative Javascript
array? For example:

var o = new Object();

o["first"] = "Adam";
o["second"] = "Eve";
o["third"] = "Cane";
o["fourth"] = "Abel";

No. The ECMAScript specification allows the contents of an object to be
unordered. Most implementations do order the contents, but you should
not rely on that.

Also, the preferred way of initializing an object is with the object
literal notation.

var o = {first: "Adam", second: "Eve", third: "Cain",
fourth: "Abel"};

See http://www.JSON.org
 
A

Abdullah Kauchali

ZER0 said:
"chronological".. But.. try with Opera.

Just tried it with Opera 7.50 and it seems to honour the order in which it
was originally put in - the same as IE and Mozilla/FF.

Almost there, but no official sanction from the specs! :(
 
Z

ZER0

Just tried it with Opera 7.50 and it seems to honour the order in which it
was originally put in - the same as IE and Mozilla/FF.

The last Opera I've seen was 7.0; and in that version the order was
different.

So, Now Opera seems use the same order of IE and Gecko.. Good news.
Almost there, but no official sanction from the specs! :(

Yes, as I said is implementation dependent.

--
ZER0://coder.gfxer.web-designer/

~ Tutti quelli che credono nella psicocinesi, per favore alzino la mia
mano.

on air ~ "Avril Lavigne - Don't Tell Me"
 
A

Abdullah Kauchali

in message
var o = {first: "Adam", second: "Eve", third: "Cain",
fourth: "Abel"};


I don't think I can do that. The key/value pairs are unknown until runtime.

Unless, of course, I am unaware of the way to initialise the way you mention
for key/value pairs only known at runtime, then I'd be glad to learn how to
do it.

Kind regards

Abdullah
 
G

Grant Wagner

Abdullah said:
ZER0 said:
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf

[for-in statement]
"The mechanics of enumerating the properties (..) is
implementation dependent. The order of enumeration is defined by the
object. (..) "

Ho bummer! :(

Thanks for that Zero.

Now, how do I accomplish the following if the order is not guaranteed:

1. Put objects within the "collection";
2. Access each one according to the order in which they were put into the
collection.

So far, I have this:

It seems to me that the most straight-forward answer would be to create
another "collection" with index numbers beginning with 0 and then always
incrementing for additions to the collections. Once a index/offset number
is used, it cannot be reused.

So, after some additions and deletions, I'll get something like:

1, 2, 3, 7, 9, 11, 23

if I wanted to add to this collection, the next one would be 24 and so on.

Is that the most elegant solution?

Kind regards

Abdullah

That's pretty much what you do. You can wrap it in functions to make it easier
to manage:

function addToCollection(collection, collectionOrder, property, value) {
collection[property] = value;
collectionOrder.push(property);
}

function removeFromCollection(collection, collectionOrder, property) {
collection[property] = null;
for (var i = 0; i < collectionOrder.length; i++) {
if (collectionOrder == property) {
collectionOrder = null;
break;
}
}
}

function dumpCollection(collection, collectionOrder) {
var output = [];
for (var i = 0; i < collectionOrder.length; i++) {
if (collectionOrder != null) {
output.push(collection[collectionOrder]);
}
}
return output;
}

var o = new Object();
var oOrder = new Array();

addToCollection(o, oOrder, "first", "Adam");
addToCollection(o, oOrder, "second", "Eve");
addToCollection(o, oOrder, "third", "Cane");
addToCollection(o, oOrder, "fourth", "Abel");
removeFromCollection(o, oOrder, "second");
addToCollection(o, oOrder, "fifth", "Noah");
alert(dumpCollection(o, oOrder));

If you want to get really fancy, you could write a "Collection" object that
encapsulates all this functionality:

function Collection() {
var collection = {};
var order = [];

this.add = function(property, value) {
if (!this.exists(property)) {
collection[property] = value;
order.push(property);
}
}
this.remove = function(property) {
collection[property] = null;
for (var i = 0; i < order.length; i++) {
if (order == property) {
order = null;
break;
}
}
}
this.toString = function() {
var output = [];
for (var i = 0; i < order.length; i++) {
if (order != null) {
output.push(collection[order]);
}
}
return output;
}
this.getKeys = function() {
var keys = [];
for (var i = 0; i < order.length; i++) {
if (order != null) {
keys.push(order);
}
}
return keys;
}
this.update = function(property, value) {
if (value != null) {
collection[property] = value;
}
for (var i = 0; i < order.length; i++) {
if (order == property) {
order = null;
order.push(property);
break;
}
}
}
this.exists = function(property) {
return collection[property] != null;
}
}

var myCollection = new Collection();
myCollection.add("first", "Adam");
myCollection.add("second", "Eve");
myCollection.add("third", "Cane");
myCollection.add("fourth", "Abel");
myCollection.remove("second");
myCollection.add("fifth", "Noah");
alert(myCollection.toString());
alert(myCollection.getKeys());
myCollection.update("first");
alert(myCollection.toString());
alert(myCollection.exists("third"));
alert(myCollection.exists("something"));

The one thing you can't do with my code is actually store a null value in a
collection entry. If you need to be able to do that, then you should use
another object inside Collection to track if a collection entry actually
contains a value or not.

--
| Grant Wagner <[email protected]>

* Client-side Javascript and Netscape 4 DOM Reference available at:
*
http://devedge.netscape.com/library/manuals/2000/javascript/1.3/reference/frames.html

* Internet Explorer DOM Reference available at:
*
http://msdn.microsoft.com/workshop/author/dhtml/reference/dhtml_reference_entry.asp

* Netscape 6/7 DOM Reference available at:
* http://www.mozilla.org/docs/dom/domref/
* Tips for upgrading JavaScript for Netscape 7 / Mozilla
* http://www.mozilla.org/docs/web-developer/upgrade_2.html
 
A

Abdullah Kauchali

<humbling code example snipped>

OMG. Thank you so much. Beats the hell out of making the attempts on my
own!

Many thanks, once again,

Kind regards

Abdullah
 
Z

ZER0

That's pretty much what you do. You can wrap it in functions to make it easier
to manage: [cut]
If you want to get really fancy, you could write a "Collection" object that
encapsulates all this functionality:

An Additional note: This code on IE, works only for version 5.5 or major;
because it use the push() array's method.
 
G

Grant Wagner

ZER0 said:
That's pretty much what you do. You can wrap it in functions to make it easier
to manage: [cut]
If you want to get really fancy, you could write a "Collection" object that
encapsulates all this functionality:

An Additional note: This code on IE, works only for version 5.5 or major;
because it use the push() array's method.

if (typeof Array.prototype.push != 'function') {
Array.prototype.push = function() {
for (var i = 0 ; i < arguments.length ; i++) {
this[this.length] = arguments;
}
}
}

--
| Grant Wagner <[email protected]>

* Client-side Javascript and Netscape 4 DOM Reference available at:
*
http://devedge.netscape.com/library/manuals/2000/javascript/1.3/reference/frames.html

* Internet Explorer DOM Reference available at:
*
http://msdn.microsoft.com/workshop/author/dhtml/reference/dhtml_reference_entry.asp
* Netscape 6/7 DOM Reference available at:
* http://www.mozilla.org/docs/dom/domref/
* Tips for upgrading JavaScript for Netscape 7 / Mozilla
* http://www.mozilla.org/docs/web-developer/upgrade_2.html
 
Z

ZER0

if (typeof Array.prototype.push != 'function') {
[cut]

Better. :)

--
ZER0://coder.gfxer.web-designer/

~ Plagiarism is copying from one source;
research is copying from two or more
(Wilson Mizner)
 
T

Thomas 'PointedEars' Lahn

Abdullah said:
Can one rely on the order of keys inserted into an associative Javascript
array? For example:

JavaScript and other ECMAScript implementations have no built-in
concept of associative arrays.
var o = new Object();

o["first"] = "Adam";
o["second"] = "Eve";
o["third"] = "Cane";
o["fourth"] = "Abel";

That is an Object object on which alphabetic properties are added, not
an array. Try o.length or o.push(), neither is present or works, while
o.first, o.second aso. work. (If properties are identifiers, they can
be accessed both with the square bracket and the dot accessor.)

Using Mozilla/5.0 and a for-in-loop, properties are iterated in the
order of assignment, but there is no standard that specifies that.

Additional note: Even

var a = new Array();
a[0] = 42;
a["foo"] = "bar";

creates an array with *one* element, not two:

alert(a.length); // 1

var s = "";
for (var i in a)
{
s += i + " == " + a + "\n";
}
alert(s);


PointedEars
 
J

John G Harris

Thomas 'PointedEars' Lahn said:
JavaScript and other ECMAScript implementations have no built-in
concept of associative arrays.
<snip>

It's the other way round. Every ECMAScript object is an associative
array.

Even Array objects are associative arrays. It's a syntax fudge that
makes Array objects look, almost, like the arrays in other languages
with their numeric indexes.

John
 
L

Lasse Reichstein Nielsen

John G Harris said:
It's the other way round. Every ECMAScript object is an associative
array.

.... where "associative array" is just mumbo-jumbo for a mapping from
something to something. I believe the name comes from Perl, although
they could have taken it from somewhere else. It is really a misnomer,
as it has nothing to do with "real" arrays.

In, e.g., Java, I would never say "associative array". I'd just say
"Map".

/L
 
J

John G Harris

Lasse Reichstein Nielsen said:
... where "associative array" is just mumbo-jumbo for a mapping from
something to something. I believe the name comes from Perl, although
they could have taken it from somewhere else. It is really a misnomer,
as it has nothing to do with "real" arrays.

Back in the 1960s a lot of people got very excited about associative
memory. It was, at last, possible to build one with less than a roomful
of electronics. As it happens its most common use these days is in
memory caches. These are buried inside processor chips and so are not
very visible to users.

An ordinary array is built from ordinary memory. You put in a relative
address and a value comes back very, very quickly.

An associative array is built from associative memory. You put in a key
and a value comes back also very, very quickly ... if you can afford to
use a million or so transistors. It's a lot slower if you have to use
software to do it.

Altogether, "associative array" is a perfectly respectable technical
term that goes back a long way. It's wrong to complain if someone uses
it.
In, e.g., Java, I would never say "associative array". I'd just say
"Map".

In Java, what have Map and Dictionary got in common? They are both
associative arrays. It's not very clear if you have to say that one is a
Map and so is the other. And in C++ you can use array syntax, a, to
get at the values.

John
 
T

Thomas 'PointedEars' Lahn

Lasse said:
... where "associative array" is just mumbo-jumbo for a mapping from
something to something. I believe the name comes from Perl, although
they could have taken it from somewhere else. It is really a misnomer,
as it has nothing to do with "real" arrays.

In, e.g., Java, I would never say "associative array". I'd just say
"Map".

Full ACK. To me, an "array" in computer science and thus programming is
an *ordered* data structure (AIUI an "array" outside of computer science
has the property of order as well), composed of *elements*. That means,
one can access element #x or append elements at the end of to the array
directly, without iteration.

With a simple non-Array[1] ECMAScript object there are no such means
available. You cannot access property #x unless you indexed it before
and you cannot obtain the number of properties until you iterated the
object using a for-in-loop. And even then you cannot tell for sure that
these are all properties of the object (which would be then elements of
the "associative array" if you like call them so) because some may have
the NonEnum flag set and thus do not occur during iteration but yet are
present. And single properties can be read-only. I don't know of any
implementation that calls itself an "array" and that allows that kind
of data hiding and level of data integrity protection regarding the
elements of that "array".

With an Array[1] ECMAScript object there is a distinction between array
elements and object properties (as already shown). Array elements can be
refered to as object properties with a(n) (numeric) index, but not all
properties of an Array (object) are elements of the array (data structure)
it encapsules.

In contrast, in PHP for example, there are what I would consider associative
arrays or maps. If you do

$a = array();
$a['foo'] = 'bar';

or

$a = array(
'foo' => 'bar'
);

You can access $a['foo'] with $a[0] as well because it is the first
element appended to the array. (Look how the "=>" operator tells
of the mapping that is done.)

Achieving that in ECMAScript and implementations requires another data
structure similar to Array objects, which I refer to as a "collection",
as specified for example with the HTMLCollection interface of the W3C
DOM.


PointedEars
___________
[1] Note the character case!
 
G

Grant Wagner

John said:
<snip>

It's the other way round. Every ECMAScript object is an associative
array.

No, every ECMAScript object is an object that can have properties which can be
accessed using dot notation (theObject.theProperty), or "array" notation
(theObject[theProperty]).
Even Array objects are associative arrays. It's a syntax fudge that
makes Array objects look, almost, like the arrays in other languages
with their numeric indexes.

No, an Array object is a special object that represents an array. Array objects
are "magical" (as is the Location object for a similar reason) because setting
the value of an array index updates properties within the object, something that
is not possible with other objects in an ECMA-262 compliant way. The closest you
could get would be to use watch()/unwatch() in Netscape to monitor the updating
of a property and act on it to update another property:

var myArray = new Object();
myArray.blahHandler = function() {
alert('blah changed');
}
myArray.watch('blah', myArray.blahHandler);
myArray.blah = 1;

But even this doesn't approximate the behavior of the Array object, where the
updating of an arbitrary "associative array" key that is an integer updates the
length property of the object. Of course, one could argue that length isn't
updated immediately, but instead returns a "count" of the number of properties
attached to the Array object, but in that case, Array would still be "magical",
with .length acting as a method call without "()" (and it seems pretty obvious
from speed tests that .length doesn't actually execute any code to "count" the
number of entries but is, at it appears to be, a simple property containing a
value).

By the way, Location is "magical" because it behaves in a way that is impossible
if it were a normal object When you do window.location.href =
'http://www.yahoo.com'; and window.location = 'http://www.yahoo.com'; and they
result in the same action, it would be like expecting:

var location = new Object();
location.href = 'http://www.yahoo.com';

and

var location = new Object();
location = 'http://www.yahoo.com';

to have the same outcome.

--
| Grant Wagner <[email protected]>

* Client-side Javascript and Netscape 4 DOM Reference available at:
*
http://devedge.netscape.com/library/manuals/2000/javascript/1.3/reference/frames.html

* Internet Explorer DOM Reference available at:
*
http://msdn.microsoft.com/workshop/author/dhtml/reference/dhtml_reference_entry.asp

* Netscape 6/7 DOM Reference available at:
* http://www.mozilla.org/docs/dom/domref/
* Tips for upgrading JavaScript for Netscape 7 / Mozilla
* http://www.mozilla.org/docs/web-developer/upgrade_2.html
 
L

Lasse Reichstein Nielsen

Grant Wagner said:
By the way, Location is "magical" because it behaves in a way that is impossible
if it were a normal object When you do window.location.href =
'http://www.yahoo.com'; and window.location = 'http://www.yahoo.com'; and they
result in the same action, it would be like expecting:

<nitpick>
Technically, it would be both the location object and the window
object that are magical.

In both cases, assigning to a property will have a different effect
than the expected one. For the location object, assigning to the
"href" property changes the page's location, which is quite a side
effect. For the window object, assigning to the "location" property
doesn't change its value, but changes "location.href" instead.

</nitpick>
/L
 
R

rh

Grant said:
John G Harris wrote:
It's the other way round. Every ECMAScript object is an associative
array.

No, every ECMAScript object is an object that can have properties which can be
accessed using dot notation (theObject.theProperty), or "array" notation
(theObject[theProperty]).

The original statement is correct. The accessor syntax, while being
important, doesn't change the fundamental (logical) nature of the
object.
No, an Array object is a special object that represents an array. Array objects
are "magical" (as is the Location object for a similar reason) because setting
the value of an array index updates properties within the object, something that
is not possible with other objects in an ECMA-262 compliant way. The closest you
could get would be to use watch()/unwatch() in Netscape to monitor the updating
of a property and act on it to update another property:

Again, the original statement is correct.

Array objects have a special "length" property, and some special
methods (notably sort) that provide further array manipulation
functionality within the language that distinquish them from standard
objects. Nonetheless, there is no access to the underlying structure
except through the standard object accessors. Therefore, regardless of
any particular implementation, Array objects remain entirely
associative in nature within the language.

By the way, Location is "magical" because it behaves in a way that is impossible
if it were a normal object.

Yes, but host objects are outside ECMA-262, and there's all kinds of
"magic" once you step out there. :)

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

Forum statistics

Threads
473,754
Messages
2,569,527
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top