Skip to content

Instantly share code, notes, and snippets.

@getify
Last active June 2, 2020 11:07
Show Gist options
  • Save getify/913bd980026fc7ea3bdca98894752196 to your computer and use it in GitHub Desktop.
Save getify/913bd980026fc7ea3bdca98894752196 to your computer and use it in GitHub Desktop.
multiple-field sorter
var data = [
{ a: 4, b: 12, c: "elderberry" },
{ a: 2, b: 10, c: "cherry", d: 4 },
{ a: 4, b: 12, c: "durian" },
{ a: 2, b: 10, c: "cherry", },
{ a: 3, b: 12, c: "durian" },
{ a: 1, b: 10, c: "apple", },
{ a: 1, b: 11, c: "apple", },
{ a: 1, b: 11, c: "banana", },
{ a: 2, b: 10, c: "banana", },
];
[...data].sort( multiFieldSorter(["+a"]) );
// 0: {a: 1, b: 10, c: "apple"}
// 1: {a: 1, b: 11, c: "apple"}
// 2: {a: 1, b: 11, c: "banana"}
// 3: {a: 2, b: 10, c: "cherry", d: 4}
// 4: {a: 2, b: 10, c: "cherry"}
// 5: {a: 2, b: 10, c: "banana"}
// 6: {a: 3, b: 12, c: "durian"}
// 7: {a: 4, b: 12, c: "elderberry"}
// 8: {a: 4, b: 12, c: "durian"}
[...data].sort( multiFieldSorter(["-a"]) );
// 0: {a: 4, b: 12, c: "elderberry"}
// 1: {a: 4, b: 12, c: "durian"}
// 2: {a: 3, b: 12, c: "durian"}
// 3: {a: 2, b: 10, c: "cherry", d: 4}
// 4: {a: 2, b: 10, c: "cherry"}
// 5: {a: 2, b: 10, c: "banana"}
// 6: {a: 1, b: 10, c: "apple"}
// 7: {a: 1, b: 11, c: "apple"}
// 8: {a: 1, b: 11, c: "banana"}
[...data].sort( multiFieldSorter(["+a","-b"]) );
// 0: {a: 1, b: 11, c: "apple"}
// 1: {a: 1, b: 11, c: "banana"}
// 2: {a: 1, b: 10, c: "apple"}
// 3: {a: 2, b: 10, c: "cherry", d: 4}
// 4: {a: 2, b: 10, c: "cherry"}
// 5: {a: 2, b: 10, c: "banana"}
// 6: {a: 3, b: 12, c: "durian"}
// 7: {a: 4, b: 12, c: "elderberry"}
// 8: {a: 4, b: 12, c: "durian"}
[...data].sort(multiFieldSorter(["+b","+a","-c"]));
// 0: {a: 1, b: 10, c: "apple"}
// 1: {a: 2, b: 10, c: "cherry", d: 4}
// 2: {a: 2, b: 10, c: "cherry"}
// 3: {a: 2, b: 10, c: "banana"}
// 4: {a: 1, b: 11, c: "banana"}
// 5: {a: 1, b: 11, c: "apple"}
// 6: {a: 3, b: 12, c: "durian"}
// 7: {a: 4, b: 12, c: "elderberry"}
// 8: {a: 4, b: 12, c: "durian"}
// "+field" -> sort by 'field' ASC
// "-field" -> sort by 'field' DESC
// default: "+" (ASC)
function multiFieldSorter(fields = []) {
return function sortBy(o1,o2) {
for (let field of fields) {
let dir = field.charAt(0) == "-" ? 1 : -1;
field = field.substr(1);
if (o1[field] < o2[field]) {
return dir;
}
else if (o1[field] > o2[field]) {
return -1 * dir;
}
}
return 0;
};
}
@WebReflection
Copy link

maybe something more like the following?

function multiFieldSorter(fields = {}) {
   return function sortBy(o1, o2) {
      for (const field of Object.keys(fields)) {
         const dir = fields[field];
         return (o1[field] < o2[field]) * -dir;
      }
      return 0;
   };
}

so that ...

[...data].sort( multiFieldSorter({a: 1}) );
[...data].sort( multiFieldSorter({a: -1}) );
[...data].sort( multiFieldSorter({a: 1, b: -1}) );

and so on ... haven't tested it much though, but it'd feel more natural (and maybe faster too, no strings manipulation)

@getify
Copy link
Author

getify commented Nov 10, 2018

@WebReflection -- maybe it's just my sensibilities, but your version seems a bit less natural or more confusing to me, because the field sorting argument (the object) has the same shape as the actual data objects. That part confused me for a good 20 seconds while reading your example, because I was like, "wait, why is he passing the data into the sorter?" I get it now, but it surprised me at first.

@sourcegr
Copy link

sourcegr commented Mar 14, 2019

A little late to the party, but @WebReflection, your code never gets past the for so 0 is never returned.

I made this one, based on your code...

function multiFieldSorter(fields) {
   const dirs = {asc:1, desc:-1}, keys = Object.keys(fields);
   return function sort(o1, o2) {
      for (const f of keys) {
         if (o1[f] != o2[f]){
            return dirs[fields[f]] * (o1[f] < o2[f] ? -1 : 1);
         }
      }
      return 0;
   };
}

use it like

[...data].sort( multiFieldSorter({a:'asc', b:'desc'}) );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment