0

I have an array of objects that also contain IDs like so:

const arr = [
   { id: "5ffca1c771138d181c3bde0b", otherValue: 10 }, 
   { id: "5ffca1c771138d181c3bde0e", otherValue: 3}, 
   { id: "5ffca1c771138d181c3bde12", otherValue: 7},
   { id: "5ffca1c771138d181c3bde04" otherValue: 1}, 
   { id: "5ffca1c771138d181c3bde08", otherValue: 11}
]

I then have second array, that contains a subset of the IDs of the first array in a particular ordering, like so:

const arrIds = [ "5ffca1c771138d181c3bde12", "5ffca1c771138d181c3bde08"];

I now want to sort the first array, so that the ordering is the same as in the second array, meaning the ordered subset is first, and the rest follows after, so that I get something like this:

[
   { id: "5ffca1c771138d181c3bde12", otherValue: 7}, // 1st place in subset
   { id: "5ffca1c771138d181c3bde08", otherValue: 11} // 2nd place in subset
   { id: "5ffca1c771138d181c3bde0b", otherValue: 10 }, // rest
   { id: "5ffca1c771138d181c3bde0e", otherValue: 3, // rest
   { id: "5ffca1c771138d181c3bde04" otherValue: 1}, // rest
]

How does the sorting function for this look like?

Current implementation:

arr.slice().sort((a, b) => arrIds.indexOf(a) - arrIds.indexOf(b))

which results in:

   { id: "5ffca1c771138d181c3bde0b", otherValue: 10 }, 
   { id: "5ffca1c771138d181c3bde0e", otherValue: 3, 
   { id: "5ffca1c771138d181c3bde04" otherValue: 1}, 
   { id: "5ffca1c771138d181c3bde12", otherValue: 7},
   { id: "5ffca1c771138d181c3bde08", otherValue: 11},
phoebus
  • 1,280
  • 1
  • 16
  • 36
  • Does this answer your question? [How do I sort an array of objects based on the ordering of another array?](https://stackoverflow.com/questions/9755889/how-do-i-sort-an-array-of-objects-based-on-the-ordering-of-another-array) – Heretic Monkey Jan 11 '21 at 22:58
  • no, since it's not a subset – phoebus Jan 11 '21 at 22:59
  • [Edit] your question to show how you tried to implement it and how it didn't work. Also note there are 8 answers to the question; not all of them depend on it being a subset. – Heretic Monkey Jan 11 '21 at 23:02

2 Answers2

2

Below is a simple example, I've used IndexOf to get the index and sort on this for the first part,. Only slight gotcha is that -1 would be at the wrong side of the sort, so a check for this and I just return a large number to place at the end instead.

The second stage of the sort is then performed on an equality check, and it's just a simple (b-a) compare, for a descending sort.

const arr = [
   { id: "5ffca1c771138d181c3bde0b", otherValue: 10 }, 
   { id: "5ffca1c771138d181c3bde0e", otherValue: 3}, 
   { id: "5ffca1c771138d181c3bde12", otherValue: 7},
   { id: "5ffca1c771138d181c3bde04", otherValue: 1}, 
   { id: "5ffca1c771138d181c3bde08", otherValue: 11}
];

const arrIds = [ "5ffca1c771138d181c3bde12", "5ffca1c771138d181c3bde08"];

function s1(a) {
  let i = arrIds.indexOf(a.id);
  if (i < 0) i = Number.MAX_SAFE_INTEGER;
  return i;
}

arr.sort((a,b) => {
  let s = s1(a) - s1(b);
  if (s === 0) return b.otherValue - a.otherValue;
  return s;
});

console.log(arr);
Keith
  • 22,005
  • 2
  • 27
  • 44
  • 1
    Plus one, but I would change `if(i < 0) i = 100000;` to `if(i < 0)i = Infinity;` even though the Browser would probably crash with such a large Array. – StackSlave Jan 11 '21 at 23:28
  • 1
    @StackSlave Yeah, I was trying to remember what the constant was for a large integer, `Number.MAX_SAFE_INTEGER` so updated now , I'm not sure but I think `Infinity` might cause issues as it's maths are not logical.. eg. `Infinity - Infinity = NaN` etc, so could mess up the sort at `s1(a) - s1(b)` – Keith Jan 11 '21 at 23:33
  • Oops... yeah, I would do `Number.MAX_SAFE_INTEGER` instead. – StackSlave Jan 11 '21 at 23:54
0

You could use Map Object because it would make your index searching faster when sorting.

const arr = [
  { id: '5ffca1c771138d181c3bde0b', otherValue: 10 },
  { id: '5ffca1c771138d181c3bde0e', otherValue: 3 },
  { id: '5ffca1c771138d181c3bde12', otherValue: 7 },
  { id: '5ffca1c771138d181c3bde04', otherValue: 1 },
  { id: '5ffca1c771138d181c3bde08', otherValue: 11 },
];
const arrIds = ['5ffca1c771138d181c3bde12', '5ffca1c771138d181c3bde08'];
const map = new Map();
arrIds.forEach((x, i) => map.set(x, i));
arr.sort(
  (x, y) =>
    (map.get(x.id) ?? Number.MAX_VALUE) - (map.get(y.id) ?? Number.MAX_VALUE)
);
console.log(arr);
mr hr
  • 3,162
  • 2
  • 9
  • 19