Сортировка массива объектов по приоритету порядка сортировки

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

var sortPriority = "ramoklyxq";

items[
0:{data: "aizak", level: 'z'}
1:{data: "alice", level: 'r'}
2:{data: "bob", level: 'a'}
3:{data: "trinity", level: 'm'}
4:{data: "ella", level: 'z'}
5:{data: "John", level: 'z'}
6:{data: "bryan", level: 'z'}
7:{data: "sam", level: 'o'}
8:{data: "nick", level: 'k'}
9:{data: "angel", level: 'l'}
10:{data: "arla", level: 'z'}
11:{data: "marley", level: 'o'}
etc
]

i want to return as:

items[
0:{data: "alice", level: 'r'}
1:{data: "bob", level: 'a'}
2:{data: "trinity", level: 'm'}
3:{data: "marley", level: 'o'}
4:{data: "sam", level: 'o'}
5:{data: "nick", level: 'k'}
6:{data: "angel", level: 'l'}
7:{data: "aizak", level: 'z'}
8:{data: "arla", level: 'z'}
9:{data: "bryan", level: 'z'}
10:{data: "ella", level: 'z'}
11:{data: "John", level: 'z'}
etc
]

Есть ли способ отсортировать список по порядку data.level с уровня sortPriority. Если в sortPriority не существует уровня, он будет добавлен после, как в примере возврата.

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

    for (let i = 0; i < items.length; i++) {
        var list = document.getElementById('holder');
        [...list.children]
            .sort((a, b) => a.data.level > b.data.level ? 1 : -1)
            .forEach(node => list.appendChild(node));
        for (let j = 0; j < items.length; j++) {
            var list = document.getElementById('holder');
            [...list.children]
                .sort((a, b) => a.data.data > b.data.data ? 1 : -1)
                .forEach(node => list.appendChild(node));
        }
    }

Мне нужно что-то вроде этой функции с правильным приоритетом в ASC для результатов каждого уровня, чтобы я мог добавить ее в список, как показано.

Заранее спасибо.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
110
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Вы можете взять объект для заказа и отсортировать его соответствующим образом. Для того же приоритета сортируйте по строке.

const
    sortPriority = "ramoklyxq",
    data = [{ data: "aizak", level: 'z' }, { data: "alice", level: 'r' }, { data: "bob", level: 'a' }, { data: "trinity", level: 'm' }, { data: "ella", level: 'z' }, { data: "John", level: 'z' }, { data: "bryan", level: 'z' }, { data: "sam", level: 'o' }, { data: "nick", level: 'k' }, { data: "angel", level: 'l' }, { data: "arla", level: 'z' }, { data: "marley", level: 'o' }],
    order = Object.fromEntries([...sortPriority].map((c, i) => [c, i + 1]));

order.default = Number.MAX_VALUE;

data.sort((a, b) =>
    (order[a.level] || order.default) - (order[b.level] || order.default) ||
    a.data.localeCompare(b.data)
);

console.info(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

как показано во фрагменте, ``` { "data": "bryan", "level": "z" }, { "data": "arla", "level": "z" }``` arla ниже Брайана с тем же уровнем

user2730288 26.05.2024 20:07

@user2730288 user2730288 В вашем сообщении не говорилось, следует ли сохранять относительный порядок между элементами ввода с одинаковым приоритетом.

Dai 26.05.2024 20:18

@Dai да, ты прав, я забыл упомянуть, что это должно быть в порядке ASC для каждого приоритета, я отредактирую как можно скорее. Спасибо!

user2730288 26.05.2024 20:27

Я использую его внутри цикла и, похоже, работает: ``` [...list.children].sort((a, b) => (order[a.data.level] || order.default) - (order[b.data.level] || order.default) || a.data.data.localeCompare(b.data.data)) .forEach(node ​​=> list.appendChild(node)); ```. Спасибо большое вам обоим!!!

user2730288 26.05.2024 22:21

const sortPriority = "ramoklyxq";

const items = [
    {data: "aizak"  , level: 'z'},
    {data: "alice"  , level: 'r'},
    {data: "bob"    , level: 'a'},
    {data: "trinity", level: 'm'},
    {data: "ella"   , level: 'z'},
    {data: "John"   , level: 'z'},
    {data: "bryan"  , level: 'z'},
    {data: "sam"    , level: 'o'},
    {data: "nick"   , level: 'k'},
    {data: "angel"  , level: 'l'},
    {data: "arla"   , level: 'z'},
    {data: "marley" , level: 'o'}
];

////

const priorityMap = Array.from( sortPriority ).reduce( ( m, ch, idx ) => { m.set( ch, idx + 1 ); return m; }, new Map() );

const output = items
  .map( o => ({ o, order: priorityMap.get( o.level ) || Number.MAX_SAFE_INTEGER }) )
  .sort( ( x, y ) => ( x.order - y.order ) || ( x.o.data.localeCompare( y.o.data ) ) )
  .map( i => i.o )
;

console.info( output );

Самый простой способ сделать это:

const items=[{data:'aizak',level:'z'},{data:'alice',level:'r'},{data:'bob',level:'a'},{data:'trinity',level:'m'},{data:'ella',level:'z'},{data:'John',level:'z'},{data:'bryan',level:'z'},{data:'sam',level:'o'},{data:'nick',level:'k'},{data:'angel',level:'l'},{data:'arla',level:'z'},{data:'marley',level:'o'}];

items.sort( sortItemsMethod('ramoklyxq') );

console.info( items );

// sort method :

function sortItemsMethod( priorytyLevels = '' )
  {
  const
    pLlen = priorytyLevels.length + 1
  , plOrder = s => 
    {
    let x = priorytyLevels.indexOf(s);
    return (x < 0) ? ( pLlen + s.charCodeAt(0) ) : x;
    };
  return (a,b) => (plOrder(a.level) - plOrder(b.level)) || a.data.localeCompare(b.data);
  }
.as-console-wrapper{max-height:100% !important;top:0}
.as-console-row::after{display:none !important;}

Есть ли способ отсортировать список по порядку data.level с уровня sortPriority. Если в sortPriority не существует уровня, он будет добавлен после, как в примере возврата.

Чтобы отсортировать item.level в том же порядке, что и sortPriority, нам нужно присвоить каждому символу значение, зависящее от порядка. Простое решение — использовать индекс, где "r" связан со значением 0, а "q" со значением 8. Их можно сохранить на Карте для быстрого поиска:

const sortPriority = "ramoklyxq";
const priorityMap = new Map(Array.from(sortPriority, (char, index) => [char, index]));
// representation of Map instance using object notation
// Map{
//   "r": 0, "a": 1, "m": 2,
//   "o": 3, "k": 4, "l": 5,
//   "y": 6, "x": 7, "q": 8,
// }

Вышеупомянутое позволяет нам отсортировать массив на основе priorityMap с помощью:

items.sort((a, b) => priorityMap.get(a.level) - priorityMap.get(b.level)); 

Обратите внимание, что вышеизложенное работает, пока все level представлены в строке sortPriority. Поскольку это не так, нам нужно добавить значение по умолчанию. Поскольку вы хотите, чтобы все записи, отличные от sortPriority, располагались в конце, мы будем использовать число, большее, чем наибольший индекс. Например, это может быть size/length. Мы представим помощника для получения значения или значения по умолчанию.

const getPriority = (char) => priorityMap.get(char) ?? priorityMap.size;

Обратите внимание на использование ?? вместо ||. Причина использования ?? в том, что 0 считается ложным. Итак, если мы получим значение для первого символа, 0 || 9 приведет к 9, тогда как нам нужно 0. ?? возвращает правую часть только в том случае, если левая часть равна нулю (null или undefined), поэтому 0 будет возвращено. Если бы мы могли получить значение несуществующего символа, это было бы undefined ?? 9, которое возвращает 9. Это гарантирует, что не-записи будут помещены в конец, поскольку они имеют наибольшее значение.

Теперь мы можем сделать то же самое, что и раньше, но использовать помощник getPriority() вместо прямого вызова priorityMap.get().

items.sort((a, b) => getPriority(a.level) - getPriority(b.level));

Это должно соответствовать первоначальным критериям.

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

Для сортировки по data после этого вы можете просто использовать оператор ||. Возвращаемое значение 0 означает, что оба значения равны. Поскольку 0 ложно, оператор || вместо этого возвращает правую часть. Это означает, что элементы сначала будут упорядочены по уровню приоритета. Если уровни приоритета одинаковы, вместо этого мы упорядочиваем их по данным.

// SORT BY priority(level) ASC, data ASC
items.sort((a, b) => (
  getPriority(a.level) - getPriority(b.level) || a.data.localeCompare(b.data)
));

Вышеупомянутое использует localeCompare() для сравнения по алфавиту. Вот пример фрагмента, объединяющего все вышеперечисленное в примере:

const sortPriority = "ramoklyxq";
const items = [
  { data: "aizak",   level: 'z' },
  { data: "alice",   level: 'r' },
  { data: "bob",     level: 'a' },
  { data: "trinity", level: 'm' },
  { data: "ella",    level: 'z' },
  { data: "John",    level: 'z' },
  { data: "bryan",   level: 'z' },
  { data: "sam",     level: 'o' },
  { data: "nick",    level: 'k' },
  { data: "angel",   level: 'l' },
  { data: "arla",    level: 'z' },
  { data: "marley",  level: 'o' },
];

const priorityMap = new Map(Array.from(sortPriority, (char, index) => [char, index]));
const getPriority = (level) => priorityMap.get(level) ?? priorityMap.size;
items.sort((a, b) => (
  getPriority(a.level) - getPriority(b.level) || a.data.localeCompare(b.data)
));

console.info(items);

Поскольку ваш вопрос, по-видимому, касается сортировки DOM-узлов (в которые не включен HTML), вот пример того, как вы можете применить это в настройках манипуляции с DOM:

const sortPriority = "ramoklyxq";
const priorityMap = new Map(Array.from(sortPriority, (char, index) => [char, index]));
const getPriority = (char) => priorityMap.get(char) ?? priorityMap.size;

document.getElementById("sort-holder").addEventListener("click", function (event) {
  const list = document.getElementById("holder");
  const items = Array.from(list.children);
  
  items.sort((a, b) => (
    getPriority(a.dataset.level) - getPriority(b.dataset.level)
    || a.dataset.data.localeCompare(b.dataset.data)
  ));
  
  list.replaceChildren(...items);
});

// non-relevant code, for demo purposes only
document.getElementById("shuffle-holder").addEventListener("click", function (event) {
  const list = document.getElementById("holder");
  const items = Array.from(list.children);
  shuffle(items);
  list.replaceChildren(...items);
});

function shuffle(arrayLike) {
  for (let limit = arrayLike.length; limit > 1; --limit) {
    const index = limit - 1;
    const randomIndex = Math.trunc(Math.random() * limit); // random int 0 up to limit (exclusive)
    if (index === randomIndex) continue; // skip if no swap is needed
    [arrayLike[index], arrayLike[randomIndex]] = [arrayLike[randomIndex], arrayLike[index]];
  }
}
<ul id = "holder">
  <li data-data = "aizak"   data-level = "z">aizak (z)</li>
  <li data-data = "alice"   data-level = "r">alice (r)</li>
  <li data-data = "bob"     data-level = "a">bob (a)</li>
  <li data-data = "trinity" data-level = "m">trinity (m)</li>
  <li data-data = "ella"    data-level = "z">ella (z)</li>
  <li data-data = "John"    data-level = "z">John (z)</li>
  <li data-data = "bryan"   data-level = "z">bryan (z)</li>
  <li data-data = "sam"     data-level = "o">sam (o)</li>
  <li data-data = "nick"    data-level = "k">nick (k)</li>
  <li data-data = "angel"   data-level = "l">angel (l)</li>
  <li data-data = "arla"    data-level = "z">arla (z)</li>
  <li data-data = "marley"  data-level = "o">marley (o)</li>
</ul>

<button id = "sort-holder">sort</button>
<button id = "shuffle-holder">shuffle</button>

Судя по всему, будущее многословно. Не могу дождаться, пока ИИ научится редактировать так, чтобы звучать по-человечески.

Dave Newton 27.05.2024 15:43

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

3limin4t0r 27.05.2024 15:53

Другие вопросы по теме