Reputation: 927
I need sort strings. But it doesn't sort correctly when it finds spaces in string. How can I make it not to sort spaces?
const array = [
{ attributes: { name: 'abcd efg' } },
{ attributes: { name: 'Übd cd' } },
{ attributes: { name: 'Ku cdf' } },
{ attributes: { name: 'äb' } },
{ attributes: { name: 'abc' } }
]
array.sort((a, b) => {
if (a.attributes.name.toUpperCase()
.localeCompare(b.attributes.name.toUpperCase(), 'de', { sensitivity: 'base' })) { return -1 }
if (b.attributes.name.toUpperCase()
.localeCompare(b.attributes.name.toUpperCase(), 'de', { sensitivity: 'base' })) { return 1 }
return 0
})
console.log('typeof array', array)
I expect to see:
[
{ attributes: { name: 'abc' } },
{ attributes: { name: 'abcd efg' } },
{ attributes: { name: 'äb' } },
{ attributes: { name: 'Ku cdf' } },
{ attributes: { name: 'Übd cd' } }
]
Upvotes: 3
Views: 1900
Reputation: 4899
The way localCompare
works is, if the first string is smaller i.e. comes before the second string, it will return a negative number.
And if the first string is greater i.e. it comes after the second string, it will return a positive number.
This line:
if (a.attributes.name.toUpperCase()
.localeCompare(b.attributes.name.toUpperCase(), 'de', { sensitivity: 'base' })) { return -1 }
will be true even if the first string is greater or the second string is.
The problem is that if (-1)
or if(any_negative_value)
is considered true
. Even if localeCompare()
returns a negative value, your first if
statement will always execute. The second if
statement will never be executed. Therefore, no matter if the a.attributes.name
is lexicographically greater or b.attributes.name
is greater, the first if
statement will always be executed.
You do not need the if
statements. The sort
function just needs the number returned by localCompare()
.
Hence, you can simply return the value of localeCompare()
and it will sort the attributes correctly.
const array = [
{ attributes: { name: 'abcd efg' } },
{ attributes: { name: 'Übd cd' } },
{ attributes: { name: 'Ku cdf' } },
{ attributes: { name: 'ab' } }
]
array.sort(
(a, b) => a
.attributes
.name
.toUpperCase()
.localeCompare(b
.attributes
.name
.toUpperCase(),
'de',
{ sensitivity: 'base' }
)
);
console.log('typeof array', array)
Upvotes: 2
Reputation: 63524
You don't need to remove the spaces. Just using the lowercase version of the strings works.
const array = [
{ attributes: { name: 'abcd efg' } },
{ attributes: { name: 'Übd cd' } },
{ attributes: { name: 'Ku cdf' } },
{ attributes: { name: 'ab' } }
];
const sensitivity = { sensitivity: 'base' };
function getLocale(a, b) {
return a['localeCompare'](b, 'de', sensitivity);
}
array.sort((a, b) => {
const al = a.attributes.name.toLowerCase();
const bl = b.attributes.name.toLowerCase();
return getLocale(al, bl) > getLocale(bl, al);
});
console.log('typeof array', array);
Upvotes: 1
Reputation: 272106
The String.localeCompare
method returns a number indicating whether a reference string comes before, or after, or is the same as the given string in sort order... which is the same as what Array.sort
is supposed to return:
const array = [
{ attributes: { name: "abcd efg" } },
{ attributes: { name: "Übd cd" } },
{ attributes: { name: "Ku cdf" } },
{ attributes: { name: "ab" } }
];
array.sort((a, b) => a.attributes.name.toUpperCase().localeCompare(b.attributes.name.toUpperCase(), "de", { sensitivity: "base" }));
console.log(array);
Upvotes: 4
Reputation: 688
Try this one....
var hasLeading = s => /^\S+\s\S+\s\S+$/.test(s);
var array = [
{ attributes: { name: 'abcd efg' } },
{ attributes: { name: 'Übd cd' } },
{ attributes: { name: 'Ku cdf' } },
{ attributes: { name: 'ab' } }
];
array.sort((a, b) => hasLeading(b.attributes.name.toUpperCase()) - hasLeading(a.attributes.name.toUpperCase()) || a.attributes.name.toUpperCase() > b.attributes.name.toUpperCase() || -(a.attributes.name.toUpperCase() < b.attributes.name.toUpperCase())
);
console.log(array);
Upvotes: 1