I wanna sort this array by numbers like ["owl 1", "dog 2", "bird 4"]
i tryed many methods but still the same (i need prefect solution for new programmer)
let v = ['bird 4', "owl 1", "dog 2"]
v.sort((a, b) => a - b)
console.log(v)
// expected = ["owl 1", "dog 2", "bird 4"]
CodePudding user response:
The behavior is caused by you trying to compare strings which will be done lexicographically (bird before dog before owl). You want to sort by number
though. So you need to look at the numbers only, not the word in front of the numbers. Also keep in mind that the string
"4"
is not the same as the number
4.
In order to get the desired behavior you have to parse the numbers (e.g. using Number()
or Number.parseInt()
) and then compare using those numbers.
let v = ['bird 4', "owl 1", "dog 2"]
v.sort((a,b) => Number(a.split(" ")[1]) - Number(b.split(" ")[1]));
console.log(v);
I am making the assumption that every string contains a space and after the space there is an actual number. You will need to handle cases where that is not the case if you need to.
CodePudding user response:
Extract the number from the string when you sort. The code is fragile if you use split on space, and take the second item. It is safer to remove non-number chars, and convert that to a number.
let arr = ['bird 4', "owl 1", "dog 2", "nix"]
arr.sort((a,b) => Number(a.replace(/[^\d] /g, '')) - Number(b.replace(/[^\d] /g, '')));
console.log(arr);
Learn about regex: https://twiki.org/cgi-bin/view/Codev/TWikiPresentation2018x10x14Regex
CodePudding user response:
If the solution needs to be "perfect" ( for your new programmer), then maybe the following could be an idea:
let v = ['bird 4', "owl 11", "dog 2", "horse 11"];
const res=v.map(el=>[el.split(" ") ,el]).sort(([[aw,an]],[[bw,bn]]) => an-bn||aw.localeCompare(bw)).map(([_,el])=>el);
console.log(res);
The snippet prepares a modified array by splitting all elements into their "word" and "number" parts first, then sorting the elements by looking at the "numbers" first and only if they are the same, also comparing their word parts. After that the original elements are extracted again from the temporary intermediate array.
The code is slightly longer than the one in @Mushroomator's (good!) answer, but it
- saves some computational effort by
split()
ting the elements only once - also sorts by the word parts if the numbers happen to be the same
- and it leaves the original array
v
unchanged.
The downside: it will need some more memory, at least temporarily.
Similarly to @Mushroomator's answer, this approach firmly relies on the blank between the word and number part of each element. However, if required, you could replace el.split(" ")
by something like el.match(/(\D*)(\d*)/).slice(1)
.
CodePudding user response:
You could match the number for sorting.
const
getNumber = s => s.match(/\d $/);
let v = ['bird 4', "owl 1", "dog 2"]
v.sort((a, b) => getNumber(a) - getNumber(b));
console.log(v);