JavaScript сортировка массива массивов

#javascript #arrays #sorting

#javascript #массивы #сортировка

Вопрос:

Я хочу отсортировать массив массивов на основе массива, а затем по длине элементов в массиве.

Возьмите следующий основной массив сортировки:

 const key = [
  "meraki",
  "gsuite",
  "active directory",
  "sophos",
  "manageengine"
]
  

Я хочу взять массив, который напоминает:

 const raw = [
  ["manageengine"],
  ["sophos"],
  ["active directory"],
  ["gsuite"],
  ["meraki"],
  ["sophos", "manageengine"],
  ["active directory", "sophos"],
  ["active directory", "manageengine"],
  ["gsuite", "active directory"],
  ["gsuite", "sophos"],
  ["gsuite", "manageengine"],
  ["meraki", "gsuite"],
  ["meraki", "active directory"],
  ["meraki", "sophos"],
  ["meraki", "manageengine"],
  ["active directory", "sophos", "manageengine"],
  ["gsuite", "active directory", "sophos"],
  ["gsuite", "active directory", "manageengine"],
  ["gsuite", "sophos", "manageengine"],
  ["meraki", "gsuite", "active directory"],
  ["meraki", "gsuite", "sophos"],
  ["meraki", "active directory", "sophos"],
  ["meraki", "gsuite", "manageengine"],
  ["meraki", "active directory", "manageengine"],
  ["meraki", "sophos", "manageengine"],
  ["gsuite", "active directory", "sophos", "manageengine"],
  ["meraki", "gsuite", "active directory", "sophos"],
  ["meraki", "gsuite", "active directory", "manageengine"],
  ["meraki", "gsuite", "sophos", "manageengine"],
  ["meraki", "active directory", "sophos", "manageengine"],
  ["meraki", "gsuite", "active directory", "sophos", "manageengine"]
];
  

В приведенном выше примере я хочу raw , чтобы массив был отсортирован соответственно каждому элементу в key массиве. Моей первой попыткой было сделать что-то вроде:

 const result = [];
for (const name of result) {
  const sorted = keys.filter((s) => s[0] === name);
  result.push(...sorted);
}

result.sort((a, b) => a.length - b.length);
  

Однако это учитывает только первый элемент в массиве, а не сортировку остальных элементов.

Комментарии:

1. Является ли ключ постоянным, или он изменяется с каким-либо вводом или ожидаемыми изменениями кода?

2. Я думаю, вы хотите for (const name of raw) , тогда, в этом цикле, const sorted = name.sort((a,b) => keys.indexOf(a) - keys.indexOf(b)) . Вероятно, вам понадобится какая-то рекурсивная сортировка для внешнего массива, поскольку его нужно сортировать по длине, а затем по содержимому каждого массива.

3. Во-первых, ваш «результат» содержит разные элементы из «необработанного» массива — третья строка, ["sophos", "active directory"] похоже, стала ["meraki", "active directory"] . Это просто опечатка? Во-вторых, вашим требованием было сортировать по ключу, а затем по длине , но ваш вывод — по длине, а затем по ключу — что это? Должны ли все те, которые начинаются с «meraki», отображаться первыми и сортироваться по длине, или все те, у которых есть только одна запись, должны отображаться первыми, отсортированными по ключу?

4. @ATD — Хороший улов — я обновил данные.

Ответ №1:

Для сортировки вы должны сначала проверить длину. Если оба равны, мы должны проверить позиции индекса первого элемента a / b внутри key . Если это одно и то же, перейдите к следующему элементу в обоих массивах.

В этом ответе используется тот факт, 0 что это ложное значение. Примерами являются: 0 || -1 //=> -1 и 1 || -1 //=> 1

 const key = ["meraki", "active directory", "sophos"];

const raw = [
  ["meraki"],
  ["active directory"],
  ["sophos", "active directory"],
  ["active directory", "sophos"],
  ["sophos"],
  ["meraki", "active directory", "sophos"],
];

raw.sort((a, b) => (
  a.length - b.length || a.reduce((diff, _, i) => (
    diff || key.indexOf(a[i]) - key.indexOf(b[i])
  ), 0)
));

console.log(raw);
console.table(raw); // check browser console  

Комментарии:

1. Другим вариантом было бы a.reduce((diff, a, i) => diff || key.indexOf(a) - key.indexOf(b[i]), 0) вместо upto(a.length).reduce(...) , но я презираю асимметрию в этом решении.

Ответ №2:

Рассмотрим следующий подход

 const key = [
  "meraki",
  "active directory",
  "sophos"
]
const raw = [
   ["sophos"],
   ["meraki"],
   ["active directory"],
   ["sophos", "active directory"],
   ["active directory", "sophos"],
   ["meraki", "active directory", "sophos"]
]

const compareThis = (a, b) => {
  if (a.length !== b.length) {
    return a.length - b.length
  }
  let itemFound = 0;
  for (let keyIndex in key) {
    for (let aIndex in a ) {
      if(a[aIndex] === key[keyIndex]) {
        itemFound = -1;
        break;
      }
      if(b[aIndex] === key[keyIndex]) {
        itemFound = 1;
        break;
      }
    }
    if(itemFound !== 0) { break }
  }
  return itemFound;
}

const sortedData = raw.sort(compareThis)

console.log(sortedData)  

Комментарии:

1. Примечание: вам не хватает ‘var’ в циклах ‘for’

2. Я думаю, что теперь он перевернут.

3. Не могли бы вы предоставить более широкий массив для отладки?