#javascript #arrays #sorting #firefox
#javascript #массивы #сортировка #firefox
Вопрос:
У меня есть массив объектов, к которому я пытаюсь применить 2 вида. Простая сортировка по алфавиту для свойства ‘name’, а затем сортировка по свойству ‘rank’, которое может быть либо числовым, либо нулевым. Объекты с нулевым «рангом» должны сортироваться до конца конечного массива.
Этот код работает так, как задумано в Chrome, Safari и Edge. Однако в Firefox он меняет алфавитный порядок всех объектов с нулевым «рангом».
JSFiddle: https://jsfiddle.net/6Lfu1z39 /
Код:
const data = [
{
"name": "F",
"rank": 2
},{
"name": "B",
"rank": null
},{
"name": "A",
"rank": 1
},{
"name": "E",
"rank": null
},{
"name": "D",
"rank": null
},{
"name": "C",
"rank": 2
}
]
const nameSort = (a, b) => {
const nameA = a.name.toUpperCase();
const nameB = b.name.toUpperCase();
if (nameA < nameB) {
return -1;
} else if (nameA > nameB) {
return 1;
}
return 0;
};
const rankSort = (a, b) => {
if (a.rank === null) {
return 1;
} else if (b.rank === null) {
return -1;
}
return 0;
}
console.log('name only', data.sort(nameSort));
console.log('name and rank', data.sort(nameSort).sort(rankSort));
Какой браузер здесь правильный? Или можно что-нибудь сделать, чтобы обеспечить согласованность между браузерами?
Ответ №1:
Похоже, вы возвращаете неправильное значение для одних и тех же значений для сравнения.
Например, с помощью a.rank === null
и b.rank === null вы возвращаете 1
, но правильное значение в этом случае равно нулю для возврата.
Реализация алгоритма сортировки зависит от поставщика и может возвращать разные результаты, в зависимости, например, от порядка сортировки, например, от начала или от конца.
Чтобы преодолеть эту проблему, вам необходимо реализовать алгоритм, который возвращает ноль для равных значений.
const data = [{ name: "F", rank: 2 }, { name: "B", rank: null }, { name: "A", rank: 1 }, { name: "E", rank: null }, { name: "D", rank: null }, { name: "C", rank: 2 }]
const nameSort = (a, b) => {
const nameA = a.name.toUpperCase();
const nameB = b.name.toUpperCase();
return nameA > nameB || -(nameA < nameB);
};
const rankSort = (a, b) => (a.rank === null) - (b.rank === null)
console.log('name only', data.sort(nameSort));
console.log('name and rank', data.sort(nameSort).sort(rankSort));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ответ №2:
Вот еще один подход к решению этой проблемы. Вы можете использовать комбинацию Array.prototype.sort()
и Array.prototype.filter()
метод для получения конечного результата. Сначала примените сортировку по алфавиту к свойству name . После этого используйте метод фильтра массива, чтобы поместить все свойство null ‘rank’ в конец массива.
const data = [
{
name: 'F',
rank: 2,
},
{
name: 'B',
rank: null,
},
{
name: 'A',
rank: 1,
},
{
name: 'E',
rank: null,
},
{
name: 'D',
rank: null,
},
{
name: 'C',
rank: 2,
},
];
data.sort((x, y) => x.name.localeCompare(y.name));
console.log('name only', data);
const ret = [
...data.filter((x) => x.rank !== null),
...data.filter((x) => x.rank === null),
];
console.log('name and rank', ret);