Question

I have the following requirement. I have a pair of integers which is to act as keys and another pair of integers which should act as values. That is:

obj[{key1:12,key2:23}]=[2,3];

obj[{key1:12,key2:22}]=[4,3];

obj[{key1:34,key2:12}]=[4,33];

Also finally when the population of this list is over, I would like to sequentially access the elements of the object/array.

Now it is my understanding that for such arrays which take an object as key, they are known as associative arrays and Javascript doesn't support them..

The following will be the operations I will perform on this structure :

  1. Insertion: I will have keys like (2,3) or (2,4) which I would like to insert into the array with a new keyvalue pair such as [1,2],

  2. Lookup : I may have a key pair like (2,3) which is already inserted into this array and I would like to get it back so that I can modify it.

That is something like:

if(obj[{key1:2,key2:3}])
   obj[{key1:2,key2:3}]=[2,5];
else 
   obj[{key1:2,key2:3}]=[2,-1];

Any suggestions as to how I can implement this in Javascript?

EDIT: These are the two things I tried:

First I made it as an array of objects. This approach didn't work because from looking around, I knew that in such cases, Javascript will call the toString method to get the string equivalent of the object which it will then use an index.

Second, I tried to do an object with object keys containing sub-objects. Something along the lines of this answer: Answer. However I am not sure how to get sequential access to all the elements after I am done with the insertion phase.

Was it helpful?

Solution 2

Here is an object oriented way to do it:

// Constructor
function AssociativeArray() {
  this.length = 0;
}

// Add or set value
AssociativeArray.prototype.set = function(key, value) {
  key = key.key1+'|'+key.key2;
  if(!this[key]) {
    this.length++;
  }
  this[key] = value;
};

// Lookup
AssociativeArray.prototype.get = function(key) {
  return this[key.key1+'|'+key.key2];
};

AssociativeArray.prototype.toString = function() {
  var k, arr = [];
  for(k in this) {
    if(this.hasOwnProperty(k) && k !== 'length') {
      arr.push(this[k]);
    }
  }
  return arr;
};

// Create Associative Array
var arr = new AssociativeArray();

// empty array
console.log(arr.toString(), 'length='+arr.length); // [] length=0

// add value
arr.set({key1:1, key2:2}, [1,1]);
console.log(arr.toString(), 'length='+arr.length); // [[1,1]] length=1

// add value
arr.set({key1:2, key2:1}, [2,2]);
console.log(arr.toString(), 'length='+arr.length); // [[1,1], [2,2]] length=2

// set value
arr.set({key1:2, key2:1}, [3,3]);
console.log(arr.toString(), 'length='+arr.length); // [[1,1], [3,3]] length=2

// lookup and set
if(arr.get({key1:2, key2:3})) {
  arr.set({key1:2, key2:3}, [2,5]);
} else {
  arr.set({key1:2, key2:3}, [2,-1]);
}
console.log(arr.toString(), 'length='+arr.length); // [[1, 1], [3, 3], [2, -1]] length=3

Fiddle here: http://jsbin.com/ohOwala/3/edit

OTHER TIPS

You're probably not going to like this much, but it'll at least give you a stable key:

obj[JSON.stringify({key1:12,key2:23})]=[2,3];

So, the big problem is that in an object the 'key' (really, the 'property') must be a string, or be able to be stringified. In your examples, {key1:12,key2:23} will always be stringified to [object Object]. So you'll never get a unique key. The only way to get that unique key is to really serialize it, such as by using the JSON.stringify method.

Note that on IE8 I think you have to include a JSON class.

You could use a bidimensional array

var arr = [];
arr[2] = [];
arr[2][3] = [1, 2];

Or you could use an object and access the pairs using the object properties names

obj = {
  _2_3: [1, 2],
  _2_1: [4, 1],
  _1_2: [3, 2]
};

and access them like this obj["_2_3"] or this obj._2_3

or maybe you could nest em

obj = {
  _1: {
    _2: [2,1]
  }
};

so you could access them like this obj["_1"]["_2"] or maybe this

obj = {
      1: {
        2: [2,1]
      }
    };

But you will be forced to use associatve array notation obj["1"]["2"] and as far as i know using the associative array like way for accessing objects properties isnt a good practice

I asked where the objects {key1:2,key3:2} came from because if you have control over it you can implement a toString method for those types that will take care of the Object to string conversion so it can be used as a property name.

//define keypair object type
var MyKeyPair = function(key1,key2){
  this.key1=key1;
  this.key2=key2;
};
//define tostring for this type
// later obj[aKeyPairInstance] will
// invoke the toString method
// if you don't do this then [Object object]
// would be returned for toString
MyKeyPair.prototype.toString=function(){
  //since you know there is only going to be key1 and key2
  // you could just:
  // return this.key1+":"+this.key2;
  //Here follows a more general approach but it'll cost
  // you more cpu time, if working with very large amounts
  // of data use the shorter version.
  var ret=[];
  for(thing in this){
    if(this.hasOwnProperty(thing)){
      ret.push(thing);
      ret.push(":");
      ret.push(this[thing]);
      ret.push(",");
    }
  }
  return ret.join("");
};

// make a bunch of keyPair objects
var keys = [
  new MyKeyPair(21,33),
  new MyKeyPair(22,34),
  new MyKeyPair(23,35),
  new MyKeyPair(24,36)
];

//create an object and give it properties
// based on the tostring value of the keypairs
var obj={};
for(var i = 0,len=keys.length;i<len;i++){
  obj[keys[i]]=[keys[i].key1,keys[i].key2];
};

console.log(obj);//<=this would not log any usefull info in IE
     //Use Chrome, Firefox, Opera or any other browser instead
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top