简体   繁体   中英

Order of the associative array in JavaScript by key and access by index

I have an associative array like:

var arr = {};
arr['alz'] = '15a';
arr['aly'] = '16b';
arr['alx'] = '17a';
arr['alw'] = '09c';

I need to find the previous and next key of any selected element. Say, for key 'aly' it will be 'alz' and 'alx'. If possible, I want to access the array by index rather than the key.

Currently, I am doing this using a separate array containing keys, eg

var arrkeys = ['alz','aly','alx','alw'];

Ordering of the object's properties is undefined . You can use this structure...

[{ key: 'alz', value: '15a'},
 { key: 'aly', value: '16b'},
 { key: 'alx', value: '17a'}]

... though searching for the element with the given key (like 'give me the element which key is 'alz' ) is not as straight-forward as with simple object. That's why using it like you did - providing a separate array for ordering of the indexes - is another common approach. You can attach this array to that object, btw:

var arr={};
arr['alz']='15a';
arr['aly']='16b';
arr['alx']='17a';
arr['alw']='09c';
arr._keysOrder = ['alz', 'aly', 'alx', 'alw'];

This is an object, not an array, and it sounds like you don't really want those strings to be keys.

How about a nice array?

var ar = [
  { key: 'alz', value: '15a' },
  { key: 'aly', value: '16b' },
  { key: 'alx', value: '17a' },
  { key: 'alw', value: '09c' }
];

If you have to know the order of everything, and still use the keys and values, try this:

var arr = [
    { key: 'alz', value: '15a' },
    { key: 'aly', value: '16b' },
    { key: 'alx', value: '17a' },
    { key: 'alw', value: '09c' }
]; 

You can then access them sequentially as follows: arr[0].key and arr[0].value . Similarly, you can find siblings inside of the loop with the following:

for(var i = 0; i < arr.length; i++)
{
    var previous_key = (i > 0) ? arr[(i - 1)].key : false;
    var next_key = (i < (arr.length - 1)) ? arr[(i + 1)].key : false;
}

You may try this

function sortObject(obj, order)
{
    var list=[], mapArr = [], sortedObj={};
    for(var x in obj) if(obj.hasOwnProperty(x)) list.push(x);
    for (var i=0, length = list.length; i < length; i++) {
        mapArr.push({ index: i, value: list[i].toLowerCase() });
    }
    mapArr.sort(function(a, b) {
        if(order && order.toLowerCase()==='desc')
            return a.value < b.value ? 1 : -1;
        else return a.value > b.value ? 1 : -1;
    });
    for(var i=0; i<mapArr.length;i++)
        sortedObj[mapArr[i].value]=obj[mapArr[i].value];
    return sortedObj;
}
// Call the function to sort the arr object
var sortedArr = sortObject(arr); // Ascending order A-Z
var sortedArr = sortObject(arr, 'desc'); // Descending order Z-A

DEMO .

Remember, this will return a new object and original object will remain unchanged.

How about adding some syntactic sugar in the form of an OrderedObject object? Then you could do something like this:

myObj = new OrderedObject();

myObj.add('alz', '15a');
myObj.add('aly', '16b');
myObj.add('alx', '17a');
myObj.add('alw', '09c');

console.log(myObj.keyAt(2)); // 'alx'
console.log(myObj.valueAt(3)); // '09c'
console.log(myObj.indexOf('aly')); // 1
console.log(myObj.length()) // 4
console.log(myObj.nextKey('aly')); // 'alx'

The following code makes this work. See it in action in a jsFiddle .

function OrderedObject() {
   var index = [];
   this.add = function(key, value) {
      if (!this.hasOwnProperty(key)) {
         index.push(key);
      }
      this[key] = value;
   };
   this.remove = function(key) {
      if (!this.hasOwnProperty(key)) { return; }
      index.splice(index.indexOf(key), 1);
      delete this[key];
   }
   this.indexOf = function(key) {
      return index.indexOf(key);
   }
   this.keyAt = function(i) {
      return index[i];
   };
   this.length = function() {
      return index.length;
   }
   this.valueAt = function(i) {
      return this[this.keyAt(i)];
   }
   this.previousKey = function(key) {
      return this.keyAt(this.indexOf(key) - 1);
   }
   this.nextKey = function(key) {
      return this.keyAt(this.indexOf(key) + 1);
   }
}

I made some decisions that may not work for you. For example, I chose to use an Object as the prototype rather than an Array , so that you could preserve enumerating your object with for (key in myObj) . But it didn't have to be that way. It could have been an Array , letting you use the property .length instead of the function .length() and then offering an each function that enumerates the keys, or perhaps an .object() function to return the inner object.

This could be a little awkward as you'd have to remember not to add items to the object yourself. That is, if you do myObj[key] = 'value'; then the index will not be updated. I also did not provide any methods for rearranging the order of things or inserting them at a particular position, or deleting by position. If you find my object idea useful, though, I'm sure you can figure out how to add such things.

With the newer versions of EcmaScript you can add true properties and make them non-enumerable. This would allow the new object to more seamlessly and smoothly act like the ideal OrderedObject I am imagining.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM