Как заставить localeCompare вести себя аналогично .sort(), чтобы все заглавные буквы были первыми?

#javascript #sorting

#javascript #сортировка

Вопрос:

У меня есть массив символов, который я хочу отсортировать:

 const arr = ['z', 'a', 'Z', 'A'];
  

Я хочу, чтобы порядок сортировки был следующим: символы верхнего регистра в алфавитном порядке, за которыми следуют символы нижнего регистра в алфавитном порядке:

 ['A', 'Z', 'a', 'z']
  

Это тривиально выполнить с помощью .sort() без каких-либо параметров:

 const arr = ['z', 'a', 'Z', 'A'];
arr.sort();
console.log(arr);  

Но как можно localeCompare использовать для определения одинакового относительного положения каждого символа? Опция caseFirst выглядела многообещающе:

Следует ли сортировать сначала верхний или нижний регистр. Возможные значения «upper», «lower» или «false» (используйте языковой стандарт по умолчанию); значение по умолчанию равно «false». Этот параметр можно задать с помощью свойства options или с помощью ключа расширения Unicode; если предоставлены оба параметра, свойство options имеет приоритет.

Но, похоже, это не делает того, что я хочу. Я перепробовал много вариантов:

 // Desired result: ['A', 'Z', 'a', 'z']

const arr = ['z', 'a', 'Z', 'A'];
arr.sort((a, b) => a.localeCompare(b));
console.log(arr);
arr.sort((a, b) => a.localeCompare(b, undefined, { caseFirst: 'upper' }));
console.log(arr);
arr.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'case', caseFirst: 'upper' }));
console.log(arr);
arr.sort((a, b) => a.localeCompare(b, 'en', { caseFirst: 'upper' }));
console.log(arr);
arr.sort((a, b) => a.localeCompare(b, 'kf', { caseFirst: 'upper' }));
console.log(arr);  

Я бы хотел, чтобы он выполнялся аналогично .sort() (по крайней мере, для алфавитных символов), который сравнивает кодовую точку каждого символа:

 ['A', 'Z', 'a', 'z'].forEach((char) => {
  console.log(char.charCodeAt());
});  

Конечно, я знаю, что могу просто избежать localeCompare и использовать .sort() без обратного вызова или использовать charCodeAt метод, описанный выше:

 const arr = ['z', 'a', 'Z', 'A'];
arr.sort((a, b) => a.charCodeAt() - b.charCodeAt());
console.log(arr);  

Но как бы я это сделал, используя localeCompare ?

Комментарии:

1. Я вознагражу за хороший ответ.

2. Хорошего ответа нет, как показывает ваш очень хорошо написанный вопрос. Единственный ответ — отфильтровать два массива (верхний, нижний), отсортировать каждый с помощью localeCompare() then .merge() , а затем снова собрать вместе.

3. Было бы полезно узнать, какие функции из localeCompare вы хотели.

4. @Kaiido Какие угодно функции, которые могут сравниваться лексикографически, по крайней мере, для простых алфавитных символов. Я не знаю, что это за функции и существуют ли они — подозреваю, что нет, — но если они есть, я не придирчивый. Я могу легко выполнить это без localeCompare , но мне просто было любопытно, можно ли это как-то localeCompare использовать и для этого. Это выглядит намного приятнее, чем условный оператор, и .sort() без аргументов работает только при сортировке массивов строк — не для объектов, и не тогда, когда вне контекста сортировки массива.

5. Итак … вы хотите использовать, localeCompare просто потому, что это выглядит хорошо? На самом деле вам не нужно ничего, что он делает, например, рассматривал é раньше f ?

Ответ №1:

Удалось отсортировать ваш массив лексикографически, используя это.

 const lexicalCompare = (a, b) =>
  a < b ? -1 : (a > b ? 1 : 0);

const arr = ['z', 'a', 'Z', 'A'];

console.log(arr.sort(lexicalCompare));  

Комментарии:

1. Это то же самое, что ни одна операция сортировки не сказала, что они не хотят. Они хотят использовать localeCompare (по каким причинам, я не знаю)