1

I have a need for a list type object simultaneously providing the contrary JS array behaviours of being iterable and associative. So at one point I want to run an index based walk through the members and in another I want to do 'does this key exist' and 'update the data under that key'.

I see many question in SO regarding discussions about associative arrays but this question differs because I am seeking re-usable code that wraps both behaviours. The solution can be a modifier to the array prototype, or a stand-alone object creation function. I accept that the list must be unique by key, and FYI in my case the members will be objects themselves.

Please note I know that there is no such thing as an associative array in JavaScript - I don't need that sermon. I seek the a solution for a single object with both capabilities on the same list.

Here is a rudimentary version in a working snippet. I am looking for a more fleshed out version that includes the full set of life-cycle features such as disposal, etc..

var List = function() {
  this.elements={} // assoc list of elements.
  this.elementArray=[] // plain array
  this.addElement=function (id, member) {
    this.elements[id]=member;
    this.elementArray.push(member);
    }
}

var myList = new List();

myList.addElement('V', {id: 'key2', name: 'Volvo'});
myList.addElement('A', {id: 'key4', name: 'Apple'});
myList.addElement('S', {id: 'key3', name: 'Google'});

console.log('Via iteration');
for (var i = 0; i < myList.elementArray.length; i = i + 1) {
  console.log('id=' + myList.elementArray[i].id + ' name=' + myList.elementArray[i].name); 
}

console.log('Via association');
console.log('Value of A: id=' + myList.elements['A'].id + ' name=' + myList.elements['A'].name);
console.log('Value of V: id=' + myList.elements['V'].id + ' name=' + myList.elements['V'].name);
console.log('Value of S: id=' + myList.elements['S'].id + ' name=' + myList.elements['S'].name);

6
  • 1
    The built-in Map seems to fit your requirements, as it provides both direct (.get, .has) and sequential (.entries) access. Commented Jun 8, 2017 at 8:50
  • Can you provide a link to docs? Commented Jun 8, 2017 at 8:51
  • 1
    Edited above ^^^^^ Commented Jun 8, 2017 at 8:52
  • @georg Map looks to be what I need except the Browser Compatibility table on the linked page show some gaps for IE11. Is Map considered viable cross browsers? Commented Jun 8, 2017 at 10:05
  • 1
    For older browsers there are polyfills, see e.g. stackoverflow.com/questions/34789810/… Commented Jun 8, 2017 at 10:33

1 Answer 1

2

I know this is far away from done, but it might give you a starting point, extending the Array class gives you the array's special length property (adds on push, when its modified it modifies the array itself, etc)

'use strict';

class AssociativeArray extends Array {
   constructor() {
      super();
      this.data = {};
   }
   push(key, value) {
      super.push(key);
      this.data[key] = value
   }
   *[Symbol.iterator]() {
      let nextIndex = 0;
      while(nextIndex < this.length) {
        yield this[nextIndex];
        nextIndex++;
      }
   }
}

var myAssociativeArray = new AssociativeArray();
myAssociativeArray.push("1st", "Bamieh");
myAssociativeArray.push("2nd", "value");
myAssociativeArray.push("3nd", "anotherValue");
console.log('myAssociativeArray::', myAssociativeArray);
console.log('myAssociativeArray.length::', myAssociativeArray.length);

for (let key of myAssociativeArray) {
  console.log('key::', key);
}

basically you are reimplementing the Map or the Set functions, which are natively supported in es6. its a good practice non-the-less.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.