Как отсортировать строки в JavaScript

У меня есть список объектов, которые я хочу сортировать на основе поля attr строки типа. Я попытался использовать -

list.sort(function (a, b) {
    return a.attr - b.attr
})

но обнаружил, что - не работает со строками в JavaScript. Как я могу отсортировать список объектов на основе атрибута с строкой типа?

Ответ 1

Используйте String.prototype.localeCompare для вашего примера:

list.sort(function (a, b) {
    return ('' + a.attr).localeCompare(b.attr);
})

Мы заставляем a.attr быть строкой, чтобы избежать исключений. localeCompare поддерживается начиная с Internet Explorer 6 и Firefox 1. Вы также можете увидеть следующий код, который не соответствует локали:

if (item1.attr < item2.attr)
  return -1;
if ( item1.attr > item2.attr)
  return 1;
return 0;

Ответ 2

Обновленный ответ (октябрь 2014 года)

Меня действительно раздражало этот порядок естественной сортировки строк, поэтому я потратил довольно много времени, чтобы исследовать эту проблему. Надеюсь, это поможет.

Короче говоря

localeCompare() Поддержка символов - это плохо, просто используйте его. Как указано Shog9, ответ на ваш вопрос:

return item1.attr.localeCompare(item2.attr);

Ошибки, обнаруженные во всех пользовательских реализациях упорядочения порядка естественной последовательности строк

Существует довольно много настраиваемых реализаций, пытаясь выполнить сравнение строк, более точно называемое "порядок сортировки натуральной строки"

Когда "играя" с этими реализациями, я всегда замечал какой-то странный выбор "естественного сортировки", а точнее ошибки (или пропуски в лучших случаях).

Обычно специальные символы (пробел, тире, амперсанд, скобки и т.д.) обрабатываются неправильно.

Затем вы обнаружите, что они появляются в разных местах, как правило, это может быть:

  • некоторые будут между прописными буквами "Z" и строчными буквами "a"
  • некоторые будут находиться между "9" и верхним регистром "A"
  • некоторые будут после нижнего регистра "z"

Если бы вы ожидали, что специальные символы для всех будут "сгруппированы" вместе в одном месте, за исключением специального символа пробела (который всегда будет первым символом). То есть либо все перед номерами, либо все между числами и буквами (строчные и прописные буквы "вместе" друг за другом) или все после букв.

Я пришел к выводу, что все они не могут обеспечить последовательный порядок, когда я начинаю добавлять только необычные символы (например, символы с диакритикой или символами, такие как тире, восклицательный знак и т.д.).

Исследование пользовательских реализаций:

Реализация порядка сортировки естественных строк в браузере через localeCompare()

localeCompare() старая реализация (без аргументов locales и options) поддерживается IE6 +, см. http://msdn.microsoft.com/en-us/library/ie/s4esdbwz(v=vs.94).aspx (прокрутите вниз до localeCompare ( )). Встроенный метод localeCompare() делает гораздо лучшую работу при сортировке, даже международных и специальных символов. Единственная проблема с использованием метода localeCompare() заключается в том, что "используемый язык и порядок сортировки полностью зависят от реализации" . Другими словами, при использовании localeCompare, таких как stringOne.localeCompare(stringTwo): Firefox, Safari, Chrome и IE имеют другой порядок сортировки для строк.

Исследование встроенных в браузер версий:

Сложность "упорядочения порядка натуральной сортировки"

Реализация твердого алгоритма (что означает: согласованный, но также охватывающий широкий спектр символов) - очень сложная задача. UTF8 содержит более 2000 символов и охватывает более 120 скриптов (языков). Наконец, есть некоторые спецификации для этих задач, он называется "Unicode Collation Algorithm", который можно найти на http://www.unicode.org/reports/tr10/. Вы можете найти дополнительную информацию об этом по этому вопросу. Я отправил https://softwareengineering.stackexchange.com/questions/257286/is-there-any-language-agnostic-specification-for-string-natural-sorting-order

Окончательное заключение

Поэтому, учитывая текущий уровень поддержки, предоставляемый пользовательскими реализациями javascript, с которыми я столкнулся, мы, вероятно, никогда не увидим ничего близкого к поддержке всех этих символов и скриптов (языков). Поэтому я предпочел бы использовать собственный метод localeCompare() браузера. Да, у него есть недостаток непоследовательности во всех браузерах, но базовое тестирование показывает, что оно охватывает гораздо более широкий диапазон символов, что позволяет создавать надежные и значимые порядки сортировки.

Итак, как указано Shog9, ответ на ваш вопрос:

return item1.attr.localeCompare(item2.attr);

Дальнейшее чтение:

Благодаря Shog9 хороший ответ, который поставил меня в "правильном" направлении, я верю

Ответ 3

Ответ (в современном ECMAScript)

list.sort((a, b) => (a.attr > b.attr) - (a.attr < b.attr))

Или же

list.sort((a, b) => +(a.attr > b.attr) || -(a.attr < b.attr))

Описание

Преобразование логического значения в число приводит к следующему:

  • true1
  • false0

Рассмотрим три возможных шаблона:

  • х больше, чем у: (x > y) - (y < x)1 - 01
  • х равен у: (x > y) - (y < x)0 - 00
  • x меньше, чем y: (x > y) - (y < x)0 - 1-1

(Альтернативный)

  • х больше чем у: +(x > y) || -(x < y) +(x > y) || -(x < y)1 || 0 1 || 01
  • х равен у: +(x > y) || -(x < y) +(x > y) || -(x < y)0 || 0 0 || 00
  • х меньше у: +(x > y) || -(x < y) +(x > y) || -(x < y)0 || -1 0 || -1-1

Таким образом, эти логики эквивалентны типичным функциям компаратора сортировки.

if (x == y) {
    return 0;
}
return x > y ? 1 : -1;

Ответ 4

Вы должны использовать > или < и == здесь. Таким образом, решение будет:

list.sort(function(item1, item2) {
    var val1 = item1.attr,
        val2 = item2.attr;
    if (val1 == val2) return 0;
    if (val1 > val2) return 1;
    if (val1 < val2) return -1;
});

Ответ 5

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

Из спецификации:

Section 11.9.4   The Strict Equals Operator ( === )

The production EqualityExpression : EqualityExpression === RelationalExpression
is evaluated as follows: 
- Let lref be the result of evaluating EqualityExpression.
- Let lval be GetValue(lref).
- Let rref be the result of evaluating RelationalExpression.
- Let rval be GetValue(rref).
- Return the result of performing the strict equality comparison 
  rval === lval. (See 11.9.6)

Итак, теперь мы переходим к 11.9.6

11.9.6   The Strict Equality Comparison Algorithm

The comparison x === y, where x and y are values, produces true or false. 
Such a comparison is performed as follows: 
- If Type(x) is different from Type(y), return false.
- If Type(x) is Undefined, return true.
- If Type(x) is Null, return true.
- If Type(x) is Number, then
...
- If Type(x) is String, then return true if x and y are exactly the 
  same sequence of characters (same length and same characters in 
  corresponding positions); otherwise, return false.

Это. Оператор тройного равенства, применяемый к строкам, возвращает истину, если аргументы являются абсолютно одинаковыми строками (одинаковой длины и одинаковых символов в соответствующих позициях).

Так что === будет работать в тех случаях, когда мы пытаемся сравнить строки, которые могли бы быть получены из разных источников, но которые мы знаем, в конечном итоге будут иметь одинаковые значения - достаточно распространенный сценарий для встроенных строк в нашем коде. Например, если у нас есть переменная с именем connection_state, и мы хотим знать, в каком из следующих состояний ['connecting', 'connected', 'disconnecting', 'disconnected'] прямо сейчас, мы можем напрямую использовать ===.

Но там больше. Чуть выше 11.9.4, есть короткое примечание:

NOTE 4     
  Comparison of Strings uses a simple equality test on sequences of code 
  unit values. There is no attempt to use the more complex, semantically oriented
  definitions of character or string equality and collating order defined in the 
  Unicode specification. Therefore Strings values that are canonically equal
  according to the Unicode standard could test as unequal. In effect this 
  algorithm assumes that both Strings are already in normalized form.

Хм. Что теперь? Полученные извне строки могут и, скорее всего, будут странными юникодами, и наши нежные === не сделают их справедливыми. На localeCompare приходит localeCompare.

15.5.4.9   String.prototype.localeCompare (that)
    ...
    The actual return values are implementation-defined to permit implementers 
    to encode additional information in the value, but the function is required 
    to define a total ordering on all Strings and to return 0 when comparing
    Strings that are considered canonically equivalent by the Unicode standard. 

Мы можем идти домой сейчас.

ТЛ; др;

Чтобы сравнить строки в JavaScript, используйте localeCompare; если вы знаете, что в строках нет компонентов, не относящихся к ASCII, поскольку они, например, являются внутренними программными константами, то также работает ===.

Ответ 6

Функция вложенной троичной стрелки

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

Ответ 7

В вашей работе в вашем первоначальном вопросе вы выполняете следующую операцию:

item1.attr - item2.attr

Таким образом, если предположить, что это числа (т.е. item1.attr = "1", item2.attr = "2" ), вы все равно можете использовать оператор "===" (или другие строгие оценщики) при условии, что вы обеспечиваете тип. Должно работать следующее:

return parseInt(item1.attr) - parseInt(item2.attr);

Если они являются альфаNumeric, тогда используйте localCompare().

Ответ 8

моя конечная реализация

var dataArr = {  

"hello": [{
    "id": 114,
    "keyword": "zzzzzz",
    "region": "Korea",
    "supportGroup": "administrators",
    "category": "Category2"
}, {
    "id": 115,
    "keyword": "aaaaa",
    "region": "Japan",
    "supportGroup": "developers",
    "category": "Category2"
}]

};
var sortArray = dataArr['hello'];
sortArray.sort(function(a,b) {
     if ( a.region < b.region )
       return -1;
     if ( a.region > b.region )
       return 1;
     return 0;
 } );

Ответ 9

list.sort(function(item1, item2){
    return +(item1.attr > item2.attr) || +(item1.attr === item2.attr) - 1;
}) 

Как работают образцы:

+('aaa'>'bbb')||+('aaa'==='bbb')-1
+(false)||+(false)-1
0||0-1
-1

+('bbb'>'aaa')||+('bbb'==='aaa')-1
+(true)||+(false)-1
1||0-1
1

+('aaa'>'aaa')||+('aaa'==='aaa')-1
+(false)||+(true)-1
0||1-1
0

Ответ 10

поскольку строки можно сравнивать непосредственно в javascript, это сделает работу

list.sort(function (a, b) {
    return a.attr > b.attr ? 1: -1;
})

вычитание в функции сортировки используется только тогда, когда требуется не алфавитная (числовая) сортировка и, конечно, она не работает со строками

Ответ 11

var str = ['v','a','da','c','k','l']
var b = str.join('').split('').sort().reverse().join('')
console.log(b)

Ответ 12

<!doctype html>
<html>
<body>
<p id = "myString">zyxtspqnmdba</p>
<p id = "orderedString"></p>
<script>
var myString = document.getElementById("myString").innerHTML;
orderString(myString);
function orderString(str) {
    var i = 0;
    var myArray = str.split("");
    while (i < str.length){
        var j = i + 1;
        while (j < str.length) {
            if (myArray[j] < myArray[i]){
                var temp = myArray[i];
                myArray[i] = myArray[j];
                myArray[j] = temp;
            }
            j++;
        }
        i++;
    }
    var newString = myArray.join("");
    document.getElementById("orderedString").innerHTML = newString;
}
</script>
</body>
</html>