Сортировка массива объектов в Chrome - PullRequest
21 голосов
/ 07 июля 2010

РЕДАКТИРОВАТЬ: Как отмечает kennytm ниже и после исследования себя, согласно спецификации ECMA , когда два объекта определены как равные в пользовательской сортировке, JavaScript не требуется оставить эти два объекта в том же порядке. И Chrome, и Opera являются единственными двумя основными браузерами, которые выбирают нестабильные сортировки, но другие включают Netscape 8 и 9, Kazehakaze, IceApe и некоторые другие. Команда Chromium пометила эту ошибку как «Работая как задумано», поэтому она не будет «исправлена». Если вам нужно, чтобы ваши массивы оставались в своем первоначальном порядке при равных значениях, вам нужно будет использовать какой-то дополнительный механизм (такой как приведенный выше). Возвращать 0, когда сортировка объектов фактически бессмысленна, так что не беспокойтесь. Или используйте библиотеку, которая поддерживает стабильную сортировку, такую ​​как Underscore / Lodash.


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

Во всех других браузерах, когда вы сортируете массив объектов, если два объекта принимают одно и то же значение, их порядок в обновленном массиве остается неизменным. В Chrome их порядок, по-видимому, рандомизирован. Запустите приведенный ниже код в Chrome и любом другом браузере. Вы должны понять, что я имею в виду.

У меня есть два вопроса:

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

Во-вторых, есть ли хороший способ исправить это? Единственное, о чем я могу думать, - это добавить автоматически увеличивающееся число в качестве атрибута к каждому члену массива перед сортировкой, а затем использовать это значение, когда два элемента sort сравнивают разрешение с одним и тем же значением. Другими словами, никогда не возвращайте 0.

Вот пример кода:

var x = [
{'a':2,'b':1},
{'a':1,'b':2},
{'a':1,'b':3},
{'a':1,'b':4},
{'a':1,'b':5},
{'a':1,'b':6},
{'a':0,'b':7},
]

var customSort = function(a,b) {
    if (a.a === b.a) return 0;
    if (a.a > b.a) return 1;
    return -1;
};

console.log("before sorting");
for (var i = 0; i < x.length; i++) {
    console.log(x[i].b);
}
x.sort(customSort);

console.log("after sorting");
for (var i = 0; i < x.length; i++) {
    console.log(x[i].b);
}

Во всех других браузерах я вижу, что перемещаются только первый член и последний член массива (я вижу 7,2,3,4,5,6,1), но в Chrome внутренние числа кажутся случайными.

[ПРАВИТЬ] Большое спасибо всем, кто ответил. Я думаю, что «противоречивый» не обязательно означает, что это ошибка. Кроме того, я просто хотел отметить, что мое свойство b было только примером. Фактически, я сортирую некоторые относительно широкие объекты на любую из примерно 20 клавиш в соответствии с пользовательским вводом. Даже отслеживание того, по чему пользователь последний раз сортировал, все равно не решит проблему случайности, которую я вижу. Мой обходной путь, вероятно, будет близким вариантом этого (новый код выделен):

var x = [
{'a':2,'b':1},
{'a':1,'b':2},
{'a':1,'b':3},
{'a':1,'b':4},
{'a':1,'b':5},
{'a':1,'b':6},
{'a':0,'b':7},
];
var i;

var customSort = function(a,b) {
    if (a.a === b.a) return a.customSortKey > b.customSortKey ? 1 : -1; /*NEW CODE*/
    if (a.a > b.a) return 1;
    return -1;
};

console.log("before sorting");
for (i = 0; i < x.length; i++) {console.log(x[i].b);}

for (i = 0; i < x.length; i++) {                      /*NEW CODE*/
    x[i].customSortKey = i;                           /*NEW CODE*/
}                                                     /*NEW CODE*/
x.sort(customSort);

console.log("after sorting");
for (i = 0; i < x.length; i++) {console.log(x[i].b);}

Ответы [ 3 ]

22 голосов
/ 07 июля 2010

Стандарт ECMAScript не гарантирует Array.sort стабильную сортировку .Chrome (движок V8) использует внутреннюю быструю сортировку на месте (для массивов размером ≥ 22, в противном случае сортировку вставками), что быстро, но не стабильно .исправьте это, заставьте customSort сравнить с .b, что устраняет необходимость стабильности алгоритма сортировки.

8 голосов
/ 07 июля 2010

Может быть, вы уже знаете это, но вы можете использовать массив для сортировки по нескольким столбцам и избежать этой ошибки:

var customSort = function(a,b) {
    return [a.a, a.b] > [b.a, b.b] ? 1:-1;
}
8 голосов
/ 07 июля 2010

К сожалению, сорт V8 нестабилен. Я посмотрю, смогу ли я найти ошибку Chromium по этому поводу.

Сортировка V8 теперь стабильна !

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...