简体   繁体   中英

sort object array based on string + numeric value in JavaScript

I'm trying to sort array using a function. But when the number is going to two digit sorting is not correct. Otherwise it's showing correct result. Please check the code.

this is the function:

 var arr = [{name: "a1", value: 1},{name: "a3", value: 1},{name: "a4", value: 1},{name: "a2", value: 1}]; var arr2 = [{name: "a1", value: 1},{name: "a3", value: 1},{name: "a14", value: 1},{name: "a12", value: 1}]; var sort = function (prop, arr) { prop = prop.split('.'); var len = prop.length; arr.sort(function (a, b) { var i = 0; while( i < len ) { a = a[prop[i]]; b = b[prop[i]]; i++; } if (a < b) { return -1; } else if (a > b) { return 1; } else { return 0; } }); return arr; }; arr = sort('name', arr); arr2 = sort('name', arr2); console.log(arr); // it's correct console.log(arr2); // it's not correct

In this case I'm trying to sort the array based on value of name .

You can use numeric collation with String#localeCompare . It will avoid lexicographic sorting and give you proper numeric order:

 var a = "10"; var b = "2"; console.log( //false - string "10" does not come after "2" because 1 < 2 "a > b:", a > b ); console.log( //-1 - `a` comes before `b` "a.localeCompare(b):", a.localeCompare(b) ); console.log( // 1 - `a` comes after `b` "a.localeCompare(b, undefined, {numeric: true}):", a.localeCompare(b, undefined, {numeric: true}) );

Note that this works for strings . If you also want to sort numbers, you have two easy options:

  • Cast the numbers to strings then use the string sorting with numeric collation. It will work the same and it keeps your code simple.
  • Use an if to check for what you're comparing and apply the .localeCompare logic for strings and a different logic for numbers.

Both would work but I personally prefer the first one, since it doesn't involve maintaining different cases. Thus using it in your solution gives the correct results:

 var arr = [{name: "a1", value: 1},{name: "a3", value: 1},{name: "a4", value: 1},{name: "a2", value: 1}]; var arr2 = [{name: "a1", value: 1},{name: "a3", value: 1},{name: "a14", value: 1},{name: "a12", value: 1}]; var arr3 = [{name: "a", value: 3},{name: "a", value: 1},{name: "a", value: 14},{name: "a", value: 12}]; var sort = function (prop, arr) { prop = prop.split('.'); var len = prop.length; arr.sort(function (a, b) {var i = 0; while( i < len ) { a = a[prop[i]]; b = b[prop[i]]; i++; } //cast to string a = String(a); b = String(b); return a.localeCompare(b, undefined, {numeric: true}) }); return arr; }; arr = sort('name', arr); arr2 = sort('name', arr2); console.log(arr); // it's correct console.log(arr2); // it's correct arr3 = sort('value', arr3); console.log(arr3); // it's correct

You need to split the alphabets and digits and then compare them

 var arr = [{name: "a1", value: 1},{name: "a3", value: 1},{name: "a4", value: 1},{name: "a2", value: 1}]; var arr2 = [{name: "a1", value: 1},{name: "a3", value: 1},{name: "a14", value: 1},{name: "a12", value: 1}]; var arr3 = [{name: 1, value: 1},{name: 11, value: 1},{name: 14, value: 1},{name: 12, value: 1}]; var sort = function (prop, arr) { prop = prop.split('.'); var len = prop.length; arr.sort(function (a, b) { var i = 0; while( i < len ) { a = a[prop[i]]; b = b[prop[i]]; i++; } let [key1,digit1] = (""+a).split(/(?<=[az])(?=\d)/) let [key2,digit2] = (""+b).split(/(?<=[az])(?=\d)/) return (key1 - key2) || (+digit1 - +digit2) }); return arr; }; arr = sort('name', arr); arr2 = sort('name', arr2); arr3 = sort('name', arr3) console.log(arr); // it's correct console.log(arr2); // it's not correct console.log(arr3);

Name property is of type string that is why sort is performed in lexicographical order(ie alphabetical order). You would need to parse name field to sort by number inside name.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM