Сортировать массив объектов, но первое место фиксируется - PullRequest
0 голосов
/ 20 февраля 2019

Вот пример объекта с массивом, который я хочу отсортировать:

{
  first: 'Zangief',
  second: 'Cammy'
  names: [
    {name: 'Dee Jay'},
    {name: 'Zangief'},
    {name: 'Dhalsim'}
    {name: 'Chun-Li'},
    {name: 'Blanka'},
    {name: 'Cammy'}
  ]
}

Я хочу зафиксировать Zangief на первом месте и Cammy на втором, а остальныев алфавитном порядке.

ожидаемый результат:

[
    {name: 'Zangief'},
    {name: 'Cammy'},
    {name: 'Blanka'}
    {name: 'Chun-Li'},
    {name: 'Dee Jay'},
    {name: 'Dhalsim'},
]

Я знаю, что это сортирует имена в алфавитном порядке:

obj.names.sort((a,b) => (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0));

, а затем я могу найти два имени и поместить их в первые дваместа, но есть ли функция сортировки, что можно сделать при сортировке?

Ответы [ 4 ]

0 голосов
/ 20 февраля 2019

    let obj = {
      first: 'Zangief',
      second: 'Cammy',

      names: [
        {name: 'Dee Jay'},
        {name: 'Zangief'},
        {name: 'Dhalsim'},
        {name: 'Chun-Li'},
        {name: 'Blanka'},
        {name: 'Cammy'}
      ]
    };

    obj.names.sort((a,b) => {
      // exit early, (or trigger error if it should never happen)
      if (a.name === b.name) return 0;

      // No matter what, 'Zangief' gets moved to the front.
      if (a.name === obj.first) return -1;
      if (b.name === obj.first) return 1;

      // if no Zangief, 'Cammy' always moves forward.
      if (a.name === obj.second) return -1;
      if (b.name === obj.second) return 1;

      // otherwise, normal alphabetical sorting
      return (a.name > b.name) ? 1 : -1;
    });
    
console.log(obj.names);    

В качестве альтернативы, вы можете сделать длинную однострочную строку:
filter возвращает новый массив с удаленными obj.first и obj.second.
sort затем сортирует этот новый массив на месте в соответствии с обычными правилами.
concat возвращает новый массив, добавляя этот отсортированный массив к [obj.first, obj.second], вашему «начальному» массиву.

let obj = {
  first: 'Zangief',
  second: 'Cammy',

  names: [
    {name: 'Dee Jay'},
    {name: 'Zangief'},
    {name: 'Dhalsim'},
    {name: 'Chun-Li'},
    {name: 'Blanka'},
    {name: 'Cammy'}
  ]
};

let sorted = [{name: obj.first}, {name: obj.second}]
  .concat(obj.names.filter(item => (
    ((item.name !== obj.first) && 
     (item.name !== obj.second))
  )).sort((a, b) => (a.name > b.name)
      ? 1 
      : ((b.name > a.name) ? -1 : 0)
  ));

console.log(sorted);

// simplified data structure
const first = 'Zangief';
const second= 'Cammy';

const names = [
    'Dee Jay',
    'Zangief',
    'Dhalsim',
    'Chun-Li',
    'Blanka',
    'Cammy'
];

// filter/concat (version 2) does not alter original names array.    
let sorted = [first, second]
  .concat(names.filter(name => (
    !((name == first) || (name == second))
  )).sort());
  
console.log("new sorted array, (version 2) via filter/concat: \n", sorted);

// orig array untouched
console.log("original names array (untouched): \n", names);

// custom sort, (version 1) alters the original names array.
names.sort((a,b) => {
      // 'Zangief' gets moved to the front.
      if (a === first) return -1;
      if (b === first || b === second) return 1;

      // Othwerwise 'Cammy' moves forward.
      if (a === second) return -1;
//      if (b === second) return 1;

      // all other strings: normal alphabetical sorting
      return (a, b) => (a > b) ? 1 : ((b > a) ? -1 : 0)
    });
    
console.log("names array, altered, after (version 1) sorting", names);
0 голосов
/ 20 февраля 2019

Вы можете построить объект с порядком известных и неизвестных имен и принять значение для упорядочения.

Если значение одинаковое, то сортировка по строке.

var object = { first: 'Zangief', second: 'Cammy', names: [{ name: 'Dee Jay' }, { name: 'Zangief' }, { name: 'Dhalsim' }, { name: 'Chun-Li' }, { name: 'Blanka' }, { name: 'Cammy' }] },
    order = Object.assign(
        ...['first', 'second', ''].map((k, i) => ({ [object[k]]: i + 1 }))
    );

object.names.sort(({ name: a }, { name: b }) =>
    (order[a] || order.undefined) - (order[b] || order.undefined) || a.localeCompare(b)
);

console.log(object.names);
.as-console-wrapper { max-height: 100% !important; top: 0; }
0 голосов
/ 20 февраля 2019

Вот мои 2 цента.Я не думаю, что было бы разумно жестко кодировать имена специальных names .Я бы добавил order к вашему массиву, который заставил бы сортировку переопределить порядок по умолчанию.Таким образом, тогда вам не понадобятся два свойства first и second .Если вы не можете изменить исходный массив, возможно, вам подойдет один из других ответов.

let object = {
    names: [
        { name: 'Dee Jay' },
        { name: 'Zangief', order: 1 },
        { name: 'Dhalsim' },
        { name: 'Chun-Li' },
        { name: 'Blanka' },
        { name: 'Cammy', order: 2 }
    ]
}

object.names.sort((a, b) => {
    return (a.order || Number.MAX_SAFE_INTEGER) - (b.order || Number.MAX_SAFE_INTEGER) 
           || a.name.localeCompare(b.name);

});

object.names.forEach(entry => console.log(entry.name));

Еще одна возможность, хотя мне и не очень нравится, заключалась бы в предварительной обработке массива перед новой сортировкой .Примерно так:

object.names.find( entry => entry.name === 'Zangief' ).order = 1;
object.names.find( entry => entry.name === 'Cammy' ).order = 2;
object.names.sort( /* new sort */ );

с добавленной соответствующей проверкой ошибок.Опять же, мне это не нравится, но это возможно.

0 голосов
/ 20 февраля 2019

Вы могли бы просто изменить свою функцию, чтобы она была примерно такой:

obj.names.sort((a,b) => {
    if (a.name === obj.first || (a.name === obj.second && b.name !== obj.first)){
        return -1;
    }
    return (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0);
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...