Сортировка объекта с нулевыми свойствами дает разные результаты между Firefox и Chrome

#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);