Сортировка массива строк в верхнем регистре, включая акценты

Поэтому я бродил по интернету в поисках какой-нибудь функции сортировки в 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']

Ребята, у вас есть идеи, как совместить и то, и другое?

Проверьте документ MDN sort & localeCompare, в localeCompare есть много дополнительных аргументов.

FrV 22.05.2019 11:02

@FrV Я сомневаюсь, что это возможно с localeCompare, см. stackoverflow.com/questions/54975581/…

Snow 22.05.2019 11:07

как насчет строк со смешанными регистрами?

Nina Scholz 22.05.2019 11:09

извини @MattEllen, я понял, что не понял после того, как опубликовал это, разница должна заключаться в том, чтобы поменять местами строчные и прописные буквы. Я полагаю, я должен попытаться отредактировать исходное сообщение

Aaron C. 22.05.2019 12:08

@АаронС. Спасибо! в этом есть смысл :D

Matt Ellen 22.05.2019 12:27

так что теперь вы меняете вопрос. Спасибо!

Nina Scholz 22.05.2019 12:53
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
7
6
1 604
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

Вы можете просто расширить функцию сортировки, чтобы отдавать приоритет прописным символам в начале строк:

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.log(arr);

Это приведет к тому, что 'ÁRBOL' будет отсортировано ниже "árbol". Не совсем уверен, что там будет искать ОП, но я сомневаюсь, что это оно.

Snow 22.05.2019 11:11

Это просто вопрос расширения регулярного выражения для идентификации символов верхнего регистра с акцентом. Я редактирую сообщение соответственно.

fjc 22.05.2019 11:13

Я не верю, что это возможно только с 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.log(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.log(foo);

Отсортируйте массив, и если:

  1. a оба прописные или оба строчные, отсортируйте их через localeCompare.
  2. если только a в верхнем регистре, a должен быть 1-м (возврат -1).
  3. по умолчанию (только 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.log(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.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Другие вопросы по теме