Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort an array of strings by a custom pattern

I have several arrays like:

var arr1 = ['A', 'B', 'C', 'D'], 
    arr2 = ['A', 'C', 'D'],
    arr3 = ['B', 'D'];

I now want them being sorted by a custom pattern, e.g. ['D', 'C', 'A', 'B']. I am using lodash and looking for a smart way of doing this.

like image 359
DonJuwe Avatar asked Dec 11 '22 20:12

DonJuwe


2 Answers

You can use an object to efficiently map values to sortable values:

var arr1 = [ "A", "B", "C", "D" ];

var map = { D: 1, C: 2, A: 3, B: 4 };
arr1.sort(function(x, y){ return map[x] - map[y]; });

// show result in snippet
document.write(JSON.stringify(arr1));
like image 112
Guffa Avatar answered Dec 13 '22 10:12

Guffa


The same basic idea as Guffa's solution, but with a reusable API:

var makeSorter = function(pattern) {
    var map = _.mapValues(_.invert(pattern), Number);
    return function(vals) {
        return vals.sort(function(a, b) {
            return map[a] - map[b];
        });
    };
};


var mySorter = makeSorter(['D', 'C', 'A', 'B']);
mySorter(['A', 'B', 'C', 'D']); //=> ["D", "C", "A", "B"]
mySorter(['A', 'C', 'D']); //=> ["D", "C", "A"]

If there might be values in your data not in your pattern, then you might need something slightly more complex:

var makeSorter = function(pattern) {
    var map = _.mapValues(_.invert(pattern), function(s) {return Number(s) + 1;});
    return function(vals) {
        return vals.sort(function(a, b) {
            return (map[a] || Infinity) - (map[b] || Infinity);
        });
    };
};

mySorter(['A', 'X', 'B', 'C', 'Q']); //=> ["C", "A", "B", "X", "Q"]

Also, how nice ES6 arrow functions are. This is the equivalent of the first version, in ES6:

var makeSorter = pattern => {
    let map = _.mapValues(_.invert(pattern), Number);
    return vals => vals.sort((a, b) => map[a] - map[b]);
};
like image 45
Scott Sauyet Avatar answered Dec 13 '22 08:12

Scott Sauyet