JohnSnow
JohnSnow

Reputation: 7121

Sort an Array of Objects based on key, and based on value

Consider this:

[{name:'John'},{age:25},{address:'some street'}]

As you can see none of the keys are a consistent name, so I cannot use.

arr.sort((a,b)=> a.consistentKey < b.consistentKey);

How can I go about sorting something like this, by name, and by value?

so the following sorted by key in alphabetical order should be:

[{address:'some street'},{age:25},{name:'John'}]

Upvotes: 3

Views: 2665

Answers (4)

Shannon Scott Schupbach
Shannon Scott Schupbach

Reputation: 1278

Below is the solution I would use. This solution provides a keys only sort, a values only sort, a keys then values sort, and a values then keys sort.

class FunkySort {
  sort (sortType) {
    switch (sortType) {
      case 'keysOnly':
        return data => this._sortByKey(data);
      case 'valuesOnly':
        return data => this._sortByValue(data);
      case 'valuesPrimary':
        return data => {
          data = this._sortByKey(data);
          return this._sortByValue(data);
        };
      case 'keysPrimary':
        return data => {
          data = this._sortByValue(data);
          return this._sortByKey(data);
        };
    }
  }

  _sortByKey (data) {
    return data.sort((a, b) => {
      var keyA = Object.keys(a)[0];
      var keyB = Object.keys(b)[0];
      return keyA < keyB ? -1 : keyA > keyB ? 1 : 0;
    });
  }

  _sortByValue (data) {
    return data.sort((a, b) => {
      // note that in Node >=v7 you could use `Object.values()`, but not in <v7.0
      var valueA = a[Object.keys(a)[0]];
      var valueB = b[Object.keys(b)[0]];
      return valueA < valueB ? -1 : valueA > valueB ? 1 : 0;
    });
  }
}

const dataArr = [{name:'John'},{age:25},{address:'some street'}];
const fs = new FunkySort();
fs.sort('keysPrimary')(dataArr);

Note that fs.sort is a curried function. The first call sets the type of sort to be done, so fs.sort('keysPrimary') returns a function that takes an array of objects and sorts it first by the values, and then by the keys, resulting in an array of objects sorted by key, and if there are multiple objects with the same key, those are sorted by value.

If you don't need this level of flexibility in the type of sort, then just the _sortByKey helper method should suffice.

Upvotes: 0

user663031
user663031

Reputation:

You can do this with

input.sort((a, b) => {
  const keya = Object.keys(a)[0];
  const keyb = Object.keys(b)[0];

  return keya.localeCompare(keyb) || a[keya].localeCompare(b[keyb]);
});

Using localeCompare is both shorter and more robust in the face of different language locales.

Upvotes: 0

binariedMe
binariedMe

Reputation: 4329

If you are thinking of sorting on the basis of key first and then further on values, you can try the following :

var a = [{name:'John'},{age:25},{address:'some street'}];
        
    alert(JSON.stringify(a.sort((a, b) => {
      nameA = Object.keys(a)[0];
      nameB = Object.keys(b)[0];
    
      if (nameA < nameB) {
        return -1;
      }
      if (nameA > nameB) {
        return 1;
      }
    
      // names must be equal
      return 0;
    })));

Here I have considered only one key, but you can always extend it to multiple keys and similarly you can further sort on the basis of values too.

Upvotes: 1

fny
fny

Reputation: 33605

If you extract the key name using Object.keys, then you can get the values you need to perform the comparison:

[{name: 'John'}, {age: 25}, {address:'some street'}].sort((a, b) => {
  const keyA = Object.keys(a)[0]
  const valA = a[keyA]
  const keyB = Object.keys(b)[0]
  const valB = a[keyB]

  if (keyA > keyB) {
    return 1
  } else if (keyA < keyB) {
    return -1
  } else /* equal */ {
   if (valA > valB) {
      return 1
    } else if (valA < valB) {
      return -1
    } else /* equal */ {
      return 0
    }
  }
})

Upvotes: 0

Related Questions