Tyrone Slothrop
Tyrone Slothrop

Reputation: 42457

Sort array of objects by string property value

I have an array of JavaScript objects:

var objs = [ 
    { first_nom: 'Laszlo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];

How can I sort them by the value of last_nom in JavaScript?

I know about sort(a,b), but that only seems to work on strings and numbers. Do I need to add a toString() method to my objects?

Upvotes: 4215

Views: 3447148

Answers (30)

ccpizza
ccpizza

Reputation: 31801

Sorting objects with Intl.Collator for the specific case when you want natural string sorting (i.e. ["1","2","10","11","111"]).

const files = [
 {name: "1.mp3", size: 123},
 {name: "10.mp3", size: 456},
 {name: "100.mp3", size: 789},
 {name: "11.mp3", size: 123},
 {name: "111.mp3", size: 456},
 {name: "2.mp3", size: 789},
];

const naturalCollator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});

files.sort((a, b) => naturalCollator.compare(a.name, b.name));

console.log(files);

Note: the undefined constructor argument for Intl.Collator represents the locale, which can be an explicit ISO 639-1 language code such as en, or the system default locale when undefined.

Browser support for Intl.Collator

Upvotes: 20

DanCZ
DanCZ

Reputation: 313

function compareProperty({ key, direction }) {
    return function (a, b) {
        const ap = a[key] || ''
        const bp = b[key] || ''

        return (direction === "desc" ? -1 : 1) * ((typeof ap === "string" && typeof bp === "string") ? ap.localeCompare(bp) : ap - bp)
    }
}

works with null, undefined keys. numeric, date, string, characters with diacritics are sorted as you expect.

use:

const sort = {
    key: "name",
    direction: "asc"
}

results.toSorted(compareProperty(sort))

Upvotes: 1

Muhammad Shoaib Riaz
Muhammad Shoaib Riaz

Reputation: 214

You can also add a generic function for sorting strings and numbers in ascending or descending order for example:

function sortArray({ data, key, sortingOrder }) {
    return data.sort((a, b) => {
      const firstValue = typeof a[key] === 'string' ? a[key]?.toLowerCase() : a[key];
      const secondValue = typeof b[key] === 'string' ? b[key]?.toLowerCase() : b[key];

      if (firstValue < secondValue) {
        return sortingOrder === SORT_ORDER.ASC ? -1 : 1;
      }
      if (firstValue > secondValue) {
        return sortingOrder === SORT_ORDER.ASC ? 1 : -1;
      }
      return 0;
    });
  }



const SORT_ORDER={
DES: 'Z-A',
ASC: 'A-Z'
};

var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Zwalle'     },
    { first_nom: 'Pig',    last_nom: 'Podine'   },
    { first_nom: 'Pirate', last_nom: 'Antun' }
];

const sortedArray = sortArray({
data: objs,
key: 'last_nom',
sortingOrder: SORT_ORDER.ASC
});

console.log('sorted array', sortedArray);

Upvotes: 1

Avnish Jayaswal
Avnish Jayaswal

Reputation: 459

  var objs = [ 
    { firstName: 'A', lastName: 'Mark'  }, // b
    { firstName: 'E', lastName: 'askavy' }, // a
    { firstName: 'C', lastName: 'peter' }
];

objs.sort((a,b) => {
   return a.firstName.localeCompare(b.firstName) // Sort Ascending 
}) 

objs.sort((a,b) => {
   return b.firstName.localeCompare(a.firstName) // Sort Decending
}) 

 console.log(objs)

Upvotes: 5

Zia
Zia

Reputation: 683

I do like below.

var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];

objs.sort(function(a, b) {
  const nameA = a.name.toUpperCase(); // ignore upper and lowercase
  const nameB = b.name.toUpperCase(); // ignore upper and lowercase
  if (nameA < nameB) {
    return -1;
  }
  if (nameA > nameB) {
    return 1;
  }
  // names must be equal
  return 0;
});

console.log(arr);

Upvotes: 2

DonCarleone
DonCarleone

Reputation: 859

let propName = 'last_nom';

let sorted_obj = objs.sort((a,b) => {
    if(a[propName] > b[propName]) {
        return 1;
    }
    if (a[propName] < b[propName]) {
        return -1;
    }
    return 0;
}

//This works because the js built-in sort function allows us to define our
//own way of sorting, this funny looking function is simply telling `sort` how to
//determine what is larger. 
//We can use `if(a[propName] > b[propName])` because string comparison is already built into JS
//if you try console.log('a' > 'z' ? 'a' : 'z')
//the output will be 'z' as 'a' is not greater than 'z'
//The return values 0,-1,1 are how we tell JS what to sort on. We're sorting on the last_nom property of the object. 
//When sorting a list it comes down to comparing two items and how to determine which one of them is "larger". 
//We need a way to tell JS how to determine which one is larger. 
//The sort defining function will use the case that returns a 1 to mean that a > b
//and the case that returns -1 to mean that a < b

Upvotes: 7

Force Bolt
Force Bolt

Reputation: 1221

Try this way:

let objs = [
        { first_nom: 'Lazslo', last_nom: 'Jamf'     },
        { first_nom: 'Pig',    last_nom: 'Bodine'   },
        { first_nom: 'Pirate', last_nom: 'Prentice' }
    ];

const compareBylastNom = (a, b) => {
    // Converting to uppercase to have case-insensitive comparison
    const name1 = a.last_nom.toUpperCase();
    const name2 = b.last_nom.toUpperCase();

    let comparison = 0;

    if (name1 > name2) {
        comparison = 1;
    } else if (name1 < name2) {
        comparison = -1;
    }
    return comparison;
}

console.log(objs.sort(compareBylastNom));

Upvotes: 1

Behnam Shomali
Behnam Shomali

Reputation: 863

Additional desc parameters for Ege Özcan's code:

function dynamicSort(property, desc) {
    if (desc) {
        return function (a, b) {
            return (a[property] > b[property]) ? -1 : (a[property] < b[property]) ? 1 : 0;
        }
    }
    return function (a, b) {
        return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
    }
}

Upvotes: 12

Burak Keceli
Burak Keceli

Reputation: 953

You may need to convert them to the lowercase form in order to prevent from confusion.

objs.sort(function (a, b) {

    var nameA = a.last_nom.toLowerCase(), nameB = b.last_nom.toLowerCase()

    if (nameA < nameB)
      return -1;
    if (nameA > nameB)
      return 1;
    return 0;  // No sorting
})

Upvotes: 11

David Morrow
David Morrow

Reputation: 9354

Underscore.js

Use Underscore.js]. It’s small and awesome...

sortBy_.sortBy(list, iterator, [context]) Returns a sorted copy of list, ranked in ascending order by the results of running each value through iterator. Iterator may also be the string name of the property to sort by (eg. length).

var objs = [
  { first_nom: 'Lazslo',last_nom: 'Jamf' },
  { first_nom: 'Pig', last_nom: 'Bodine'  },
  { first_nom: 'Pirate', last_nom: 'Prentice' }
];

var sortedObjs = _.sortBy(objs, 'first_nom');

Upvotes: 247

Wogan
Wogan

Reputation: 72727

It's easy enough to write your own comparison function:

function compare( a, b ) {
  if ( a.last_nom < b.last_nom ){
    return -1;
  }
  if ( a.last_nom > b.last_nom ){
    return 1;
  }
  return 0;
}

objs.sort( compare );

Or inline (c/o Marco Demaio):

objs.sort((a,b) => (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0))

Or simplified for numeric (c/o Andre Figueiredo):

objs.sort((a,b) => a.last_nom - b.last_nom); // b - a for reverse sort

Upvotes: 5784

agershun
agershun

Reputation: 4107

Acording your example, you need to sort by two fields (last name, first name), rather than one. You can use the Alasql library to make this sort in one line:

var res = alasql('SELECT * FROM ? ORDER BY last_nom, first_nom',[objs]);

Try this example at JSFiddle.

Upvotes: 8

Eduardo Cuomo
Eduardo Cuomo

Reputation: 19006

Using xPrototype's sortBy:

var o = [
  { Name: 'Lazslo', LastName: 'Jamf'     },
  { Name: 'Pig',    LastName: 'Bodine'   },
  { Name: 'Pirate', LastName: 'Prentice' },
  { Name: 'Pag',    LastName: 'Bodine'   }
];


// Original
o.each(function (a, b) { console.log(a, b); });
/*
 0 Object {Name: "Lazslo", LastName: "Jamf"}
 1 Object {Name: "Pig", LastName: "Bodine"}
 2 Object {Name: "Pirate", LastName: "Prentice"}
 3 Object {Name: "Pag", LastName: "Bodine"}
*/


// Sort By LastName ASC, Name ASC
o.sortBy('LastName', 'Name').each(function(a, b) { console.log(a, b); });
/*
 0 Object {Name: "Pag", LastName: "Bodine"}
 1 Object {Name: "Pig", LastName: "Bodine"}
 2 Object {Name: "Lazslo", LastName: "Jamf"}
 3 Object {Name: "Pirate", LastName: "Prentice"}
*/


// Sort by LastName ASC and Name ASC
o.sortBy('LastName'.asc, 'Name'.asc).each(function(a, b) { console.log(a, b); });
/*
 0 Object {Name: "Pag", LastName: "Bodine"}
 1 Object {Name: "Pig", LastName: "Bodine"}
 2 Object {Name: "Lazslo", LastName: "Jamf"}
 3 Object {Name: "Pirate", LastName: "Prentice"}
*/


// Sort by LastName DESC and Name DESC
o.sortBy('LastName'.desc, 'Name'.desc).each(function(a, b) { console.log(a, b); });
/*
 0 Object {Name: "Pirate", LastName: "Prentice"}
 1 Object {Name: "Lazslo", LastName: "Jamf"}
 2 Object {Name: "Pig", LastName: "Bodine"}
 3 Object {Name: "Pag", LastName: "Bodine"}
*/


// Sort by LastName DESC and Name ASC
o.sortBy('LastName'.desc, 'Name'.asc).each(function(a, b) { console.log(a, b); });
/*
 0 Object {Name: "Pirate", LastName: "Prentice"}
 1 Object {Name: "Lazslo", LastName: "Jamf"}
 2 Object {Name: "Pag", LastName: "Bodine"}
 3 Object {Name: "Pig", LastName: "Bodine"}
*/

Upvotes: 5

Morteza Tourani
Morteza Tourani

Reputation: 3536

I just enhanced Ege Özcan's dynamic sort to dive deep inside objects.

If the data looks like this:

obj = [
    {
        a: { a: 1, b: 2, c: 3 },
        b: { a: 4, b: 5, c: 6 }
    },
    {
        a: { a: 3, b: 2, c: 1 },
        b: { a: 6, b: 5, c: 4 }
}];

And if you want to sort it over a a.a property, I think my enhancement helps very well. I add new functionality to objects like this:

Object.defineProperty(Object.prototype, 'deepVal', {
    enumerable: false,
    writable: true,
    value: function (propertyChain) {
        var levels = propertyChain.split('.');
        parent = this;
        for (var i = 0; i < levels.length; i++) {
            if (!parent[levels[i]])
                return undefined;
            parent = parent[levels[i]];
        }
        return parent;
    }
});

And changed _dynamicSort's return function:

return function (a, b) {
    var result = ((a.deepVal(property) > b.deepVal(property)) - (a.deepVal(property) < b.deepVal(property)));
    return result * sortOrder;
}

And now you can sort by a.a. this way:

obj.sortBy('a.a');

See the complete script in a JSFiddle.

Upvotes: 3

Gil Epshtain
Gil Epshtain

Reputation: 9821

This is a simple problem. I don't know why people have such complex solutions.

A simple sort function (based on the quicksort algorithm):

function sortObjectsArray(objectsArray, sortKey)
{
    // Quick Sort:
    var retVal;

    if (1 < objectsArray.length)
    {
        var pivotIndex = Math.floor((objectsArray.length - 1) / 2);  // Middle index
        var pivotItem = objectsArray[pivotIndex];                    // Value in the middle index
        var less = [], more = [];

        objectsArray.splice(pivotIndex, 1);                          // Remove the item in the pivot position
        objectsArray.forEach(function(value, index, array)
        {
            value[sortKey] <= pivotItem[sortKey] ?                   // Compare the 'sortKey' proiperty
                less.push(value) :
                more.push(value) ;
        });

        retVal = sortObjectsArray(less, sortKey).concat([pivotItem], sortObjectsArray(more, sortKey));
    }
    else
    {
        retVal = objectsArray;
    }

    return retVal;
}

Use example:

var myArr =
        [
            { val: 'x', idx: 3 },
            { val: 'y', idx: 2 },
            { val: 'z', idx: 5 },
        ];

myArr = sortObjectsArray(myArr, 'idx');

Upvotes: 8

Vlad Bezden
Vlad Bezden

Reputation: 89735

In ES6/ES2015 or later you can do it this way:

objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));

Prior to ES6/ES2015

objs.sort(function(a, b) {
    return a.last_nom.localeCompare(b.last_nom)
});

Upvotes: 1083

jmwierzbicki
jmwierzbicki

Reputation: 177

I came into the problem of sorting array of objects, with changing the priority of values. Basically I want to sort an array of peoples by their age, and then by surname - or just by surname, name.

I think that this is simplest solution compared to other answers.

It’s is used by calling sortPeoples(['array', 'of', 'properties'], reverse=false).

/////////////////////// Example array of peoples ///////////////////////

var peoples = [
    {name: "Zach", surname: "Emergency", age: 1},
    {name: "Nancy", surname: "Nurse", age: 1},
    {name: "Ethel", surname: "Emergency", age: 1},
    {name: "Nina", surname: "Nurse", age: 42},
    {name: "Anthony", surname: "Emergency", age: 42},
    {name: "Nina", surname: "Nurse", age: 32},
    {name: "Ed", surname: "Emergency", age: 28},
    {name: "Peter", surname: "Physician", age: 58},
    {name: "Al", surname: "Emergency", age: 58},
    {name: "Ruth", surname: "Registration", age: 62},
    {name: "Ed", surname: "Emergency", age: 38},
    {name: "Tammy", surname: "Triage", age: 29},
    {name: "Alan", surname: "Emergency", age: 60},
    {name: "Nina", surname: "Nurse", age: 58}
];


//////////////////////// Sorting function /////////////////////
function sortPeoples(propertyArr, reverse) {
    function compare(a, b) {
        var i = 0;
        while (propertyArr[i]) {
            if (a[propertyArr[i]] < b[propertyArr[i]])
                return -1;
            if (a[propertyArr[i]] > b[propertyArr[i]])
                return 1;
            i++;
        }
        return 0;
    }
    peoples.sort(compare);

    if (reverse) {
        peoples.reverse();
    }
};

//////////////// End of sorting method ///////////////
function printPeoples() {
    $('#output').html('');
    peoples.forEach(function(person) {
        $('#output').append(person.surname + " " + person.name + " " + person.age + "<br>");
    })
}
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>

<html>

    <body>

        <button onclick="sortPeoples(['surname']); printPeoples()">sort by ONLY by surname ASC results in mess with same name cases</button><br>
        <button onclick="sortPeoples(['surname', 'name'], true); printPeoples()">sort by surname then name DESC</button><br>
        <button onclick="sortPeoples(['age']); printPeoples()">sort by AGE ASC. Same issue as in first case</button><br>
        <button onclick="sortPeoples(['age', 'surname']); printPeoples()">sort by AGE and Surname ASC. Adding second field fixed it.</button><br>

        <div id="output"></div>
    </body>

</html>

Upvotes: 2

Tero Tolonen
Tero Tolonen

Reputation: 4254

There are many good answers here, but I would like to point out that they can be extended very simply to achieve a lot more complex sorting. The only thing you have to do is to use the OR operator to chain comparison functions like this:

objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )

Where fn1, fn2, ... are the sort functions which return [-1,0,1]. This results in "sorting by fn1" and "sorting by fn2" which is pretty much equal to ORDER BY in SQL.

This solution is based on the behaviour of || operator which evaluates to the first evaluated expression which can be converted to true.

The simplest form has only one inlined function like this:

// ORDER BY last_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )

Having two steps with last_nom,first_nom sort order would look like this:

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) ||
                  a.first_nom.localeCompare(b.first_nom)  )

A generic comparison function could be something like this:

// ORDER BY <n>
let cmp = (a,b,n)=>a[n].localeCompare(b[n])

This function could be extended to support numeric fields, case-sensitivity, arbitrary data types, etc.

You can use them by chaining them by sort priority:

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> cmp(a,b, "last_nom") || cmp(a,b, "first_nom") )
// ORDER_BY last_nom, first_nom DESC
objs.sort((a,b)=> cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
// ORDER_BY last_nom DESC, first_nom DESC
objs.sort((a,b)=> -cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )

The point here is that pure JavaScript with functional approach can take you a long way without external libraries or complex code. It is also very effective, since no string parsing have to be done.

Upvotes: 35

ravshansbox
ravshansbox

Reputation: 748

One more option:

var someArray = [...];

function generateSortFn(prop, reverse) {
    return function (a, b) {
        if (a[prop] < b[prop]) return reverse ? 1 : -1;
        if (a[prop] > b[prop]) return reverse ? -1 : 1;
        return 0;
    };
}

someArray.sort(generateSortFn('name', true));

It sorts ascending by default.

Upvotes: 15

Luke Schoen
Luke Schoen

Reputation: 4533

Sort an array of objects

// Data
var booksArray = [
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];

// Property to sort by
var args = "last_nom";

// Function to sort the data by the given property
function sortByProperty(property) {
    return function (a, b) {
        var sortStatus = 0,
            aProp = a[property].toLowerCase(),
            bProp = b[property].toLowerCase();
        if (aProp < bProp) {
            sortStatus = -1;
        } else if (aProp > bProp) {
            sortStatus = 1;
        }
        return sortStatus;
    };
}

// Implementation
var sortedArray = booksArray.sort(sortByProperty(args));

console.log("sortedArray: " + JSON.stringify(sortedArray) );

Console log output:

"sortedArray: 
[{"first_nom":"Pig","last_nom":"Bodine"},
{"first_nom":"Lazslo","last_nom":"Jamf"},
{"first_nom":"Pirate","last_nom":"Prentice"}]"

Adapted based on this source: Code Snippet: How to Sort An Array of JSON Objects By Property

Upvotes: 5

depiction
depiction

Reputation: 819

This will sort a two-level nested array by the property passed to it in alphanumeric order.

function sortArrayObjectsByPropAlphaNum(property) {
    return function (a,b) {
        var reA = /[^a-zA-Z]/g;
        var reN = /[^0-9]/g;
        var aA = a[property].replace(reA, '');
        var bA = b[property].replace(reA, '');

        if(aA === bA) {
            var aN = parseInt(a[property].replace(reN, ''), 10);
            var bN = parseInt(b[property].replace(reN, ''), 10);
            return aN === bN ? 0 : aN > bN ? 1 : -1;
        } else {
            return a[property] > b[property] ? 1 : -1;
        }
    };
}

Usage:

objs.sort(utils.sortArrayObjectsByPropAlphaNum('last_nom'));

Upvotes: 2

a8m
a8m

Reputation: 9474

I didn't see any implementation similar to mine. This version is based on the Schwartzian transform idiom.

function sortByAttribute(array, ...attrs) {
  // Generate an array of predicate-objects containing
  // property getter, and descending indicator
  let predicates = attrs.map(pred => {
    let descending = pred.charAt(0) === '-' ? -1 : 1;
    pred = pred.replace(/^-/, '');
    return {
      getter: o => o[pred],
      descend: descending
    };
  });
  // Schwartzian transform idiom implementation. AKA "decorate-sort-undecorate"
  return array.map(item => {
    return {
      src: item,
      compareValues: predicates.map(predicate => predicate.getter(item))
    };
  })
  .sort((o1, o2) => {
    let i = -1, result = 0;
    while (++i < predicates.length) {
      if (o1.compareValues[i] < o2.compareValues[i])
        result = -1;
      if (o1.compareValues[i] > o2.compareValues[i])
        result = 1;
      if (result *= predicates[i].descend)
        break;
    }
    return result;
  })
  .map(item => item.src);
}

Here's an example how to use it:

let games = [
  { name: 'Mashraki',          rating: 4.21 },
  { name: 'Hill Climb Racing', rating: 3.88 },
  { name: 'Angry Birds Space', rating: 3.88 },
  { name: 'Badland',           rating: 4.33 }
];

// Sort by one attribute
console.log(sortByAttribute(games, 'name'));
// Sort by mupltiple attributes
console.log(sortByAttribute(games, '-rating', 'name'));

Upvotes: 25

Partha Roy
Partha Roy

Reputation: 1621

So here is one sorting algorithm which can sort in any order, throughout array of any kind of objects, without the restriction of datatype comparison (i.e., Number, String, etc.):

function smoothSort(items,prop,reverse) {
    var length = items.length;
    for (var i = (length - 1); i >= 0; i--) {
        //Number of passes
        for (var j = (length - i); j > 0; j--) {
            //Compare the adjacent positions
            if(reverse){
              if (items[j][prop] > items[j - 1][prop]) {
                //Swap the numbers
                var tmp = items[j];
                items[j] = items[j - 1];
                items[j - 1] = tmp;
            }
            }

            if(!reverse){
              if (items[j][prop] < items[j - 1][prop]) {
                  //Swap the numbers
                  var tmp = items[j];
                  items[j] = items[j - 1];
                  items[j - 1] = tmp;
              }
            }
        }
    }

    return items;
}
  • the first argument items is the array of objects,

  • prop is the key of the object on which you want to sort,

  • reverse is a Boolean parameter which on being true results in ascending order and in false it returns descending order.

Upvotes: 2

sg28
sg28

Reputation: 1387

I will give you a solution implementing a selection sort algorithm. It is simple and effective.

var objs = [
  { first_nom: 'Lazslo', last_nom: 'Jamf'     },
  { first_nom: 'Pig',    last_nom: 'Bodine'   },
  { first_nom: 'Pirate', last_nom: 'Prentice' }
];


function selection_Sort(num) {
  //console.log(num);
  var temp, index;
  for (var i = 0; i <= num.length - 1; i++) {
    index = i;

    for (var j = i + 1; j <= num.length - 1; j++) {
      // You can use first_nom/last_nom, any way you choose to sort

      if (num[j].last_nom < num[index].last_nom) {
        index = j;
      }
    }

    // Below is the swapping part
    temp = num[i].last_nom;
    num[i].last_nom = num[index].last_nom;
    num[index].last_nom = temp;
  };
  console.log(num);
  return num;
}

selection_Sort(objs);

Upvotes: 1

Nico Van Belle
Nico Van Belle

Reputation: 5156

Lodash (a superset of Underscore.js).

It's good not to add a framework for every simple piece of logic, but relying on well tested utility frameworks can speed up development and reduce the amount of bugs.

Lodash produces very clean code and promotes a more functional programming style. In one glimpse, it becomes clear what the intent of the code is.

The OP's issue can simply be solved as:

const sortedObjs = _.sortBy(objs, 'last_nom');

More information? For example, we have the following nested object:

const users = [
  { 'user': {'name':'fred', 'age': 48}},
  { 'user': {'name':'barney', 'age': 36 }},
  { 'user': {'name':'wilma'}},
  { 'user': {'name':'betty', 'age': 32}}
];

We now can use the _.property shorthand user.age to specify the path to the property that should be matched. We will sort the user objects by the nested age property. Yes, it allows for nested property matching!

const sortedObjs = _.sortBy(users, ['user.age']);

Want it reversed? No problem. Use _.reverse.

const sortedObjs = _.reverse(_.sortBy(users, ['user.age']));

Want to combine both using chain?

const { chain } = require('lodash');
const sortedObjs = chain(users).sortBy('user.age').reverse().value();

Or when do you prefer flow over chain?

const { flow, reverse, sortBy } = require('lodash/fp');
const sortedObjs = flow([sortBy('user.age'), reverse])(users);

Upvotes: 45

Damjan Pavlica
Damjan Pavlica

Reputation: 34073

Old answer that is not correct:

arr.sort((a, b) => a.name > b.name)

UPDATE

From Beauchamp's comment:

arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))

More readable format:

arr.sort((a, b) => {
  if (a.name < b.name) return -1
  return a.name > b.name ? 1 : 0
})

Without nested ternaries:

arr.sort((a, b) => a.name < b.name ? - 1 : Number(a.name > b.name))

Explanation: Number() will cast true to 1 and false to 0.

Upvotes: 69

karthik006
karthik006

Reputation: 951

Using Lodash or Underscore.js, it’s a piece of cake:

const sortedList = _.orderBy(objs, [last_nom], [asc]); // Ascending or descending

Upvotes: 4

Francois Girard
Francois Girard

Reputation: 348

A simple function that sorts an array of object by a property:

function sortArray(array, property, direction) {
    direction = direction || 1;
    array.sort(function compare(a, b) {
        let comparison = 0;
        if (a[property] > b[property]) {
            comparison = 1 * direction;
        } else if (a[property] < b[property]) {
            comparison = -1 * direction;
        }
        return comparison;
    });
    return array; // Chainable
}

Usage:

var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];

sortArray(objs, "last_nom"); // Asc
sortArray(objs, "last_nom", -1); // Desc

Upvotes: 12

Harun Or Rashid
Harun Or Rashid

Reputation: 5947

Way 1:

You can use Underscore.js. Import underscore first.

 import * as _ from 'underscore';
 let SortedObjs = _.sortBy(objs, 'last_nom');

Way 2: Use a compare function.

function compare(first, second) {
     if (first.last_nom < second.last_nom)
         return -1;
     if (first.last_nom > second.last_nom)
       return 1;
    return 0;
 }

objs.sort(compare);

Upvotes: 7

Jadli
Jadli

Reputation: 860

This sorting function can be used for all object sorting:

  • object
  • deepObject
  • numeric array

You can also do ascending or descending sort by passing 1, -1 as the parameter.

Object.defineProperty(Object.prototype, 'deepVal', {
    enumerable: false,
    writable: true,
    value: function (propertyChain) {
        var levels = propertyChain.split('.');
        parent = this;
        for (var i = 0; i < levels.length; i++) {
            if (!parent[levels[i]])
                return undefined;
            parent = parent[levels[i]];
        }
        return parent;
    }
});

function dynamicSortAll(property, sortOrders=1) {

    /** The default sorting will be ascending order. If
        you need descending order sorting you have to
        pass -1 as the parameter **/

    var sortOrder = sortOrders;

    return function (a, b) {

        var result = (property? ((a.deepVal(property) > b.deepVal(property)) ? 1 : (a.deepVal(property) < b.deepVal(property)) ? -1 : 0) : ((a > b) ? 1 : (a < b) ? -1 : 0))

        return result * sortOrder;
    }
}

deepObj = [
    {
        a: { a: 1, b: 2, c: 3 },
        b: { a: 4, b: 5, c: 6 }
    },
    {
        a: { a: 3, b: 2, c: 1 },
        b: { a: 6, b: 5, c: 4 }
}];

let deepobjResult = deepObj.sort(dynamicSortAll('a.a', 1))
console.log('deepobjResult: ' + JSON.stringify(deepobjResult))
var obj = [
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];
let objResult = obj.sort(dynamicSortAll('last_nom', 1))
console.log('objResult: ' + JSON.stringify(objResult))

var numericObj = [1, 2, 3, 4, 5, 6]

let numResult = numericObj.sort(dynamicSortAll(null, -1))
console.log('numResult: ' + JSON.stringify(numResult))

let stringSortResult = 'helloworld'.split('').sort(dynamicSortAll(null, 1))

console.log('stringSortResult: ' + JSON.stringify(stringSortResult))

let uniqueStringOrger=[...new Set(stringSortResult)];
console.log('uniqueStringOrger: ' + JSON.stringify(uniqueStringOrger))

Upvotes: 3

Related Questions