amcdnl
amcdnl

Reputation: 8638

JavaScript Sort Array of Arrays

I'm wanting to sort an array of arrays based on a array and then by length of items in the array.

Take the following master sort array:

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

I want to take a array that resembles:

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"]
];

In the above example, I want the raw array to be sorted by accordingly to each item in the key array. My first attempt was to do something like:

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

However that only takes into account the first item in the array, not the sort of the rest of the items.

Upvotes: 0

Views: 120

Answers (2)

3limin4t0r
3limin4t0r

Reputation: 21110

To sort you have to first check the length. If both are equal we have to check the index positions of the first element of a/b within key. If those are the same move on to the next element in both arrays.

This answer makes use of the fact that 0 is a falsey value. Examples are: 0 || -1 //=> -1 and 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

Upvotes: 1

Owen Kelvin
Owen Kelvin

Reputation: 15098

Consider below approach

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)

Upvotes: 1

Related Questions