Is array both associative and indexed?

68,077

Solution 1

There are no such things as associative arrays in Javascript. You can use object literals, which look like associative arrays, but they have unordered properties. Regular Javascript arrays are based on integer indexes, and can't be associative.

For example, with this object:

var params = {
    foo: 1,
    bar: 0,
    other: 2
};

You can access properties from the object, for example:

params["foo"];

And you can also iterate over the object using the for...in statement:

for(var v in params) {
    //v is equal to the currently iterated property
}

However, there is no strict rule on the order of property iteration - two iterations of your object literal could return the properties in different orders.

Solution 2

After reading the Wikipedia definition of associative array, I'm going to break with traditional JavaScript lore and say, "yes, JavaScript does have associative arrays." With JavaScript arrays, you can add, reassign, remove, and lookup values by their keys (and the keys can be quoted strings), which is what Wikipedia says associative arrays should be able to do.

However, you seem to be asking something different--whether you can look up the same value by either index or key. That's not a requirement of associative arrays (see the Wikipedia article.) Associative arrays don't have to give you the ability to get a value by index.

JavaScript arrays are very closely akin to JavaScript objects.

  arr=[];
  arr[0]="zero";
  arr[1]="one";
  arr[2]="two";
  arr["fancy"]="what?";

Yes, that's an array, and yes, you can get away with non-numeric indices. (If you're curious, after all this, arr.length is 3.)

In most cases, I think you should stick to numeric indices when you use arrays. That what most programmers expect, I think.

The link is to my blog post about the subject.

Solution 3

Native JS objects only accept strings as property names, which is true even for numeric array indices; arrays differ from vanilla objects only insofar as most JS implementations will store numerically indexed properties differently (ie in an actual array as long as they are dense) and setting them will trigger additional operations (eg adjustment of the length property).

If you're looking for a map which accepts arbitrary keys, you'll have to use a non-native implementation. The script is intended for fast iteration and not random-access by numeric indices, so it might nor be what you're looking for.

A barebones implementation of a map which would do what you're asking for could look like this:

function Map() {
    this.length = 0;
    this.store = {};
}

Map.prototype.get = function(key) {
    return this.store.hasOwnProperty(key) ?
        this.store[key] : undefined;
};

Map.prototype.put = function(key, value, index) {
    if(arguments.length < 3) {
        if(this.store.hasOwnProperty(key)) {
            this.store[key].value = value;
            return this;
        }

        index = this.length;
    }
    else if(index >>> 0 !== index || index >= 0xffffffff)
        throw new Error('illegal index argument');

    if(index >= this.length)
        this.length = index + 1;

    this[index] = this.store[key] =
        { index : index, key : key, value : value };

    return this;
};

The index argument of put() is optional.

You can access the values in a map map either by key or index via

map.get('key').value
map[2].value

Solution 4

var myArray = Array();
myArray["first"] = "Object1";
myArray["second"] = "Object2";
myArray["third"] = "Object3";

Object.keys(myArray);              // returns ["first", "second", "third"]
Object.keys(myArray).length;       // returns 3

if you want the first element then you can use it like so:

myArray[Object.keys(myArray)[0]];  // returns "Object1"

Solution 5

The order in which objects appear in an associative javascript array is not defined, and will differ across different implementations. For that reason you can't really count on a given associative key to always be at the same index.

EDIT:

as Perspx points out, there aren't really true associative arrays in javascript. The statement foo["bar"] is just syntactic sugar for foo.bar

If you trust the browser to maintain the order of elements in an object, you could write a function

function valueForIndex(obj, index) {

    var i = 0;
    for (var key in obj) {

        if (i++ == index)
            return obj[key];
    }
}
Share:
68,077
puffpio
Author by

puffpio

wheeeee @puffpio

Updated on July 17, 2022

Comments

  • puffpio
    puffpio almost 2 years

    Can an array in JavaScript be associative AND indexed?

    I'd like to be able to lookup an item in the array by its position or a key value.

  • Paolo Bergantino
    Paolo Bergantino almost 15 years
    Although this is a true, in practice all major browsers loop over the properties of an object in the order in which they were defined. This is not in the spec, of course, but it's worth a mention.
  • Nosredna
    Nosredna almost 15 years
    Actually, JavaScript arrays can have non-integer indices as well. It just doesn't have much in the way of methods for dealing with them.
  • user5880801
    user5880801 almost 15 years
    You were right when you said "And you can have an array with non-numeric indices". It slipped my mind somehow, but I know this fact.
  • BaroqueBobcat
    BaroqueBobcat almost 15 years
    To be pedantic, "fancy" is not an index in the array, but an attribute of the array instance object.
  • roryf
    roryf almost 15 years
    You mean like a string? in that case it isn't an array, just an object with properties.
  • Nosredna
    Nosredna almost 15 years
    Yeah, good point. That's why I say that arrays are closely related to objects in JavaScript.
  • linusthe3rd
    linusthe3rd almost 15 years
    Nosredna: JS arrays do not have key indices, those JS objects are considered object literals. so: foo["bar"] = 1; foo.bar === foo["bar"]; //true foo["bar"] === foo[0]; //false This is one of the many subtle quirks about JS that throw people off easily.
  • Miles
    Miles almost 15 years
    +1, but I would lose "numerically indexed properties will be stored differently": that's not necessarily the case, and isn't required by the spec.
  • Miles
    Miles almost 15 years
    @BaroqueBobcat: to be really pedantic :) indices in the array are just properties ("attributes") of the array instance object; an array just treats specially those properties which are the string form of an integer with regards to the length property.
  • puffpio
    puffpio almost 15 years
    but then stuff.length would not be 1 anymore since you added .bar right? thus looping through by index wouldnt really work anymore..
  • NickFitz
    NickFitz almost 15 years
    No - adding a named property doesn't increase the length; only adding an element by numeric index increases length. Adding "stuff[1000] = 'blah'" would cause the length to increase to 1001, even though only two numerically-indexed elements and one named property have actually been added. Fun isn't it ;-)
  • Amit Patil
    Amit Patil about 14 years
    JavaScript Objects, including Arrays, have only string indices. a[1] is actually saying a['1'].
  • Chris
    Chris over 13 years
    How do you put? map.put('key','value') and map[2].value = val ?
  • Christoph
    Christoph over 13 years
    map.put('key','value') for appending a value and map.put('key','value', 42) for inserting a value at a given position; map[42].value = 'value' will also work (ie replace the value of an existing key-value-pair), but you can't change the key or index of the entry or add new entries this way
  • Lightness Races in Orbit
    Lightness Races in Orbit almost 13 years
    It's not pedantic at all. It's an incredibly important distinction, made evident when you start trying to serialise your array into, say, JSON. The value with a non-numeric key is not part of the array data. (And strictly speaking, you're breaking your array by not using .push().)
  • Ryan
    Ryan about 12 years
    Oh and if you are going to do this in a loop you will likely need closures btw... just saying.
  • kontur
    kontur over 11 years
    I downvoted this answer, because while it might be possible to use syntaxt that looks like an array, this is not proper javascript nor a proper array. Your answer is good for reference, but should have a clear reminder that this is NOT how you'd conventionally use arrays.
  • z.a.
    z.a. over 8 years
    Arrays should be able to be indexed so when it's iterated, it is returned in order, but here it's not the case.
  • Daniel Sokolowski
    Daniel Sokolowski about 6 years
    This is the approach I took, but with a syntax showing the association at assignment which I found more to my liking aSignals[aSignals.length] = aSignals['fooBar'] = { 'sKey': 'foobBar', ... }
  • gujralam
    gujralam over 3 years
    The latest MDN documentation makes it quiet clear that Array index must be integers. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • Scott Marcus
    Scott Marcus over 3 years
    JavaScript does not have associative arrays. Your answer is talking about objects, not arrays.
  • Scott Marcus
    Scott Marcus over 3 years
    I know this is an old post, but to be clear, JavaScript does not have associative arrays and you cannot pass a string index to an array. What you are talking about here is an object with keys.