Toniq
Toniq

Reputation: 5006

Sort array on key value

I have a function which sorts by name currently and an array of value / key pairs.

I wonder how can I pass the key on which sort is being performed so I can call the same function every time like so:

var arr = [{name:'bob', artist:'rudy'},
           {name:'johhny', artist:'drusko'},
           {name:'tiff', artist:'needell'},
           {name:'top', artist:'gear'}];

sort(arr, 'name');   //trying to sort by name
sort(arr, 'artist'); //trying to sort by artist

function sort(arr) {
  arr.sort(function(a, b) {
    var nameA=a.name.toLowerCase(), nameB=b.name.toLowerCase();
    if (nameA < nameB) //sort string ascending
      return -1;
    if (nameA > nameB)
      return 1;
    return 0; //default return value (no sorting)
   });          
}

Upvotes: 20

Views: 87170

Answers (5)

KooiInc
KooiInc

Reputation: 122936

[edit 2020/08/14] This was rather an old answer and not very good as well, so simplified and revised.

Create a function that returns the sorting lambda (the Array.prototype.sort callback that does the actual sorting). That function can receive the key name, the kind of sorting (string (case sensitive or not) or numeric) and the sorting order (ascending/descending). The lambda uses the parameter values (closure) to determine how to sort.

const log = (...strs) => 
  document.querySelector("pre").textContent += `\n${strs.join("\n")}`;
const showSortedValues = (arr, key) => 
  ` => ${arr.reduce((acc, val) => ([...acc, val[key]]), [])}`;
  
// the actual sort lamda factory function
const sortOnKey = (key, string, desc) => {
  const caseInsensitive = string && string === "CI";
  return (a, b) => {
    a = caseInsensitive ? a[key].toLowerCase() : a[key];
    b = caseInsensitive ? b[key].toLowerCase() : b[key];
    if (string) {
      return desc ? b.localeCompare(a) : a.localeCompare(b);
    }
    return desc ? b - a : a - b;
  }
};

// a few examples
const onNameStringAscendingCaseSensitive = 
  getTestArray().sort( sortOnKey("name", true) );
const onNameStringAscendingCaseInsensitive = 
  getTestArray().sort( sortOnKey("name", "CI", true) );
const onValueNumericDescending = 
  getTestArray().sort( sortOnKey("value", false, true) );

// examples
log(`*key = name, string ascending case sensitive`,
  showSortedValues(onNameStringAscendingCaseSensitive, "name")
);

log(`\n*key = name, string descending case insensitive`,
  showSortedValues(onNameStringAscendingCaseInsensitive, "name")
);

log(`\n*key = value, numeric desc`, 
  showSortedValues(onValueNumericDescending, "value")
);

function getTestArray() {
  return [{
    name: 'Bob',
    artist: 'Rudy',
    value: 23,
  }, {
    name: 'John',
    artist: 'Drusko',
    value: 123,
  }, {
    name: 'Tiff',
    artist: 'Needell',
    value: 1123,
  }, {
    name: 'Top',
    artist: 'Gear',
    value: 11123,
  }, {
    name: 'john',
    artist: 'Johanson',
    value: 12,
  }, ];
}
<pre></pre>

Upvotes: 20

Michael Guild
Michael Guild

Reputation: 834

Make your life easy and use a closure https://stackoverflow.com/a/31846142/1001405

You can see the working example here

var filter = 'name', //sort by name
data = [{name:'bob', artist:'rudy'},{name:'johhny', artist:'drusko'},{name:'tiff', artist:'needell'},{name:'top', artist:'gear'}];; 

var compare = function (filter) {
    return function (a,b) { //closure
        var a = a[filter],
            b = b[filter];

        if (a < b) {
            return -1;
        }else if (a > b) {
            return 1;
        } else {
            return 0;
        }
    };
};

filter = compare(filter); //set filter

console.log(data.sort(filter));

Upvotes: 2

Jake
Jake

Reputation: 507

Looking at all the answers, I came up with my own solution that works cross-browser. The accepted solution does not work in IE or Safari. Also, the other solutions do not allow for sorting by descending.

/*! FUNCTION: ARRAY.KEYSORT(); **/
Array.prototype.keySort = function(key, desc){
  this.sort(function(a, b) {
    var result = desc ? (a[key] < b[key]) : (a[key] > b[key]);
    return result ? 1 : -1;
  });
  return this;
}

var arr = [{name:'bob', artist:'rudy'}, {name:'johhny', artist:'drusko'}, {name:'tiff', artist:'needell'}, {name:'top', artist:'gear'}];
arr.keySort('artist');
arr.keySort('artist', true);

Upvotes: 1

Phaedrus
Phaedrus

Reputation: 497

function keysrt(key) {
  return function(a,b){
   if (a[key] > b[key]) return 1;
   if (a[key] < b[key]) return -1;
   return 0;
  }
}

someArrayOfObjects.sort(keysrt('text'));

Upvotes: 8

Diode
Diode

Reputation: 25155

Array.prototype.sortOn = function(key){
    this.sort(function(a, b){
        if(a[key] < b[key]){
            return -1;
        }else if(a[key] > b[key]){
            return 1;
        }
        return 0;
    });
}



var arr = [{name:'bob', artist:'rudy'},{name:'johhny', artist:'drusko'},{name:'tiff', artist:'needell'},{name:'top', artist:'gear'}];

arr.sortOn("name");
arr.sortOn("artist");

Upvotes: 46

Related Questions