问题
There have been other questions about How to compare arrays in JavaScript?. What I want to know is the most straightforward way to write/use a three-way comparison function like the one required by Array.sort(). Here's an example using the default one which doesn't work well:
> [ [4,5,10], [4,5,6], [4,1,2] ].sort() // no compare function, uses the default one
[ [ 4, 1, 2 ],
[ 4, 5, 10 ], // oops, string sorting makes 10 < 6
[ 4, 5, 6 ] ]
This is what I came up with:
// return -1 if lhs is "less" than rhs, +1 if "greater", and 0 if equal
// if lhs and rhs have different lengths, only the shorter part will be considered
function compareArrays(lhs, rhs) {
for (var ii = 0; ii < lhs.length; ii++) {
if (lhs[ii] < rhs[ii]) {
return -1;
} else if (lhs[ii] > rhs[ii]) {
return 1;
}
}
return 0;
}
Which gives us what we want:
> [ [4,5,10], [4,5,6], [4,1,2] ].sort(compareArrays)
[ [ 4, 1, 2 ],
[ 4, 5, 6 ],
[ 4, 5, 10 ] ]
Is there something more like a one-liner, or must I define my own function whenever I want to do this?
Supporting old browsers is not a requirement. Using libraries like jQuery or Underscore is OK.
One way to look at this is "The first nonzero value from a standard three-way compare applied to each pair of elements." But even then I haven't found a good fit in existing libraries.
回答1:
I'd go with a generic comparison-maker function to be used in a functional way:
function compareArrays(compareItems) {
return function(a, b) {
for (var r, i=0, l=Math.min(a.length, b.length); i<l; i++)
if (0 != (r = compareItems(a[i], b[i])))
return r;
return a.length - b.length;
};
}
// Examples:
var compareNumberArrays = compareArray(function(a,b){ return a-b; }),
compareGenericArrays = compareArray(function(a,b){ return +(a>b)||-(b>a); });
Now you can use
[ [4,5,10], [4,5,6], [4,1,2], [4,5] ].sort(compareNumberArrays)
Is there something more like a one-liner, or must I define my own function whenever I want to do this?
Comparing arrays is too complex for a one-liner, you should use a helper function. There's no built-in one that you can use everywhere.
回答2:
Probably not the shortest possible, but the fewest lines I can get to sensibly is:
function compareArrays(lhs, rhs) {
var result;
lhs.some(function(v, i) {
return (result = v - rhs[i]);
});
return result;
}
or less sensibly:
function compareArrays(lhs, rhs, r) {
lhs.some(function(v, i) {return (r = v - rhs[i])});
return r;
}
Edit
Seems you don't want numbers. The compare part can be any relationship you want, e.g. for strings:
function compareArrays(lhs, rhs, r) {
lhs.some(function(v, i) {return (r = v < rhs[i]? -1 : v > rhs[i]? 1 : 0)});
return r;
}
[['a','b','c'],['a','c','d'],['a','b','d']].sort(compareArrays) // a,b,c,a,b,d,a,c,d
But the compare function needs to know what it's getting so it doesn't sort numbers as strings or strings as numbers (and so on…).
回答3:
If you know that they are always triplets of numbers (arrays of length 3), you could do this:
function combineNum(array) {
return (array[0] * 100) + (array[1] * 10) + array[2];
}
function compareArrays(lhs, rhs) {
return combineNum(rhs) - combineNum(lhs);
}
来源:https://stackoverflow.com/questions/23881838/three-way-compare-function-for-arrays-in-javascript