Поэтому я бродил по интернету в поисках какой-нибудь функции сортировки в js. Вот в чем проблема. У нас есть такой массив строк:
['único', 'UNICO', 'árbol', 'ARBOL', 'cosas', 'COSAS', 'fútbol', 'FUTBOL']
и мы хотим что-то вроде этого (сначала в верхнем регистре):
['ARBOL', 'COSAS', 'FUTBOL', 'UNICO', 'árbol', 'cosas', 'fútbol', 'único']
или вот так (сначала строчные):
['árbol', 'cosas', 'fútbol', 'único', 'ARBOL', 'COSAS', 'FUTBOL', 'UNICO']
Дело в том, что это очень легко получить:
['ARBOL', 'COSAS', 'FUTBOL', 'UNICO', 'cosas', 'fútbol', 'árbol','único']
с функцией .sort();
, но нам не нужны слова с ударением в конце, поэтому мы используем
.sort(function(a, b) {
return a.localCompare(b);
});
но мы заканчиваем с этим...
['ARBOL', 'árbol', 'COSAS', 'cosas', 'FUTBOL', 'fútbol', 'UNICO', 'único']
Ребята, у вас есть идеи, как совместить и то, и другое?
@FrV Я сомневаюсь, что это возможно с localeCompare
, см. stackoverflow.com/questions/54975581/…
как насчет строк со смешанными регистрами?
извини @MattEllen, я понял, что не понял после того, как опубликовал это, разница должна заключаться в том, чтобы поменять местами строчные и прописные буквы. Я полагаю, я должен попытаться отредактировать исходное сообщение
@АаронС. Спасибо! в этом есть смысл :D
так что теперь вы меняете вопрос. Спасибо!
Вы можете просто расширить функцию сортировки, чтобы отдавать приоритет прописным символам в начале строк:
const arr = ['ÁRBOL', 'único', 'UNICO', 'árbol', 'ARBOL', 'cosas', 'COSAS', 'fútbol', 'FUTBOL'];
function startsWithUppercase(str) {
return str.substr(0, 1).match(/[A-Z\u00C0-\u00DC]/);
}
arr.sort(function(a, b) {
if (startsWithUppercase(a) && !startsWithUppercase(b)) {
return -1;
} else if (startsWithUppercase(b) && !startsWithUppercase(a)) {
return 1;
}
return a.localeCompare(b);
});
console.info(arr);
Это приведет к тому, что 'ÁRBOL'
будет отсортировано ниже "árbol"
. Не совсем уверен, что там будет искать ОП, но я сомневаюсь, что это оно.
Это просто вопрос расширения регулярного выражения для идентификации символов верхнего регистра с акцентом. Я редактирую сообщение соответственно.
Я не верю, что это возможно только с localeCompare
, см.:
Как заставить localeCompare вести себя аналогично .sort(), чтобы все заглавные буквы шли первыми?:
Но вы можете комбинировать описанный метод здесь с sort
:
const arr = ['único', 'UNICO', 'árbol', 'ARBOL', 'cosas', 'COSAS', 'fútbol', 'FUTBOL'];
const norm = str => str.normalize('NFD').replace(/[\u0300-\u036f]/g, "")
arr.sort((a, b) => Number(norm(a) > norm(b)) || -(Number(norm(b) > norm(a))));
console.info(arr);
// ['ARBOL', 'COSAS', FUTBOL', 'UNICO', 'árbol', 'cosas', 'fútbol', 'único']
Вы можете разделить их по случаям, отсортировать и собрать обратно.
let foo = ['único', 'UNICO', 'árbol', 'ARBOL', 'cosas', 'COSAS', 'fútbol', 'FUTBOL'];
foo = foo.reduce((a, b) => {
b.toUpperCase() === b ? a[0].push(b) : a[1].push(b);
return a;
}, [[],[]]).flatMap(e => e.sort((a, b) => a.localeCompare(b)));
console.info(foo);
Отсортируйте массив, и если:
a
оба прописные или оба строчные, отсортируйте их через localeCompare.a
в верхнем регистре, a должен быть 1-м (возврат -1
).b
в верхнем регистре) сначала b
(возврат 1).Примечание: это предполагает, что все слова не имеют смешанных прописных и строчных букв.
const arr = ['único', 'UNICO', 'árbol', 'ARBOL', 'cosas', 'COSAS', 'fútbol', 'FUTBOL']
arr.sort((a, b) => {
const aIsUpperCase = a.toUpperCase() === a;
const bIsUpperCase = b.toUpperCase() === b;
if (aIsUpperCase === bIsUpperCase) return a.localeCompare(b, 'es');
if (aIsUpperCase) return -1;
return 1;
})
console.info(arr)
Вы можете выполнить сортировку с картой и заменить каждый символ двумя символами, в зависимости от случая, с пробелом перед или позади персонажа. Затем отсортируйте и сопоставьте новый массив.
Example
unsorted
index value ----- -------------------- 0 'ú n i c o ' 1 ' U N I C O' 2 'á r b o l ' 3 ' A R B O L' 4 ' c o s a s ' 5 ' C O S A S' 6 ' f ú t b o l ' 7 ' F U T B O L'
sorted
index value ----- -------------------- 3 ' A R B O L' 5 ' C O S A S' 7 ' F U T B O L' 1 ' U N I C O' 4 ' c o s a s ' 6 ' f ú t b o l ' 2 'á r b o l ' 0 'ú n i c o '
var array = ['único', 'UNICO', 'árbol', 'ARBOL', 'cosas', 'COSAS', 'fútbol', 'FUTBOL'],
result = array
.map((s, index) => ({ index, value: Array.from(s, c => c === c.toUpperCase()
? ' ' + c
: c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'
? ' ' + c + ' '
: c + ' '
).join('') }))
.sort((a, b) => a.value.localeCompare(b.value))
.map(({ index }) => array[index]);
console.info(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Проверьте документ MDN sort & localeCompare, в localeCompare есть много дополнительных аргументов.