2010-07-07 2 views
21

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


У меня только что появилось сообщение о том, что какой-то код, который я написал, ломается в 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 внутренние номера кажутся рандомизированными.

[EDIT] Спасибо всем, кто ответил. Я думаю, что «непоследовательность» не обязательно означает, что это ошибка. Кроме того, я просто хотел указать, что мой объект 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);} 

ответ

7

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

+6

[V8 90 НОМЕРА: V8 не устойчивая сортировка] (HTTP: // код .google.com/p/v8/issues/detail? id = 90 «Ошибка V8 90») – lawnsea

22

Стандарт ECMAScript does not guarantee Array.sort is a stable sort. Chrome (двигатель V8) использует in-place QuickSort internally (для массивов размером ≥ 22, иначе сортировка вставки), которая быстро, но not stable.

Чтобы исправить это, сделайте customSort сравните с .b, а также устраните необходимость в стабильности алгоритма сортировки.

8

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

var customSort = function(a,b) { 
    return [a.a, a.b] > [b.a, b.b] ? 1:-1; 
} 
Смежные вопросы