1

I have two arrays and I want to sort first one based on some values from another array:

const items = [
 ['music', ['arr']],
 ['movies', ['arr']],
 ['quizes', ['arr']],
 ['series', ['arr']]
];

const categories = [
 { name: "music", priority: 3},
 { name: "movies", priority: 2},
 { name: "quizes", priority: 5},
 { name: "series", priority: 1},
 { name: "sports", priority: 4},
];

I want to sort my first array, by property 'priority' from my second array -> from the biggest one.

Like this:

const expectedResult = [
 ['quizes', ['arr']],
 ['music', ['arr']]
 ['movies', ['arr']],
 ['series', ['arr']],
];

This is what I tried but without success.

const sorted = items.sort((a,b) => {
  const [aKey, aVal] = a;
  const [bKey, bVal] = b;
 
  const prio = categories.filter(c => c.name === aKey)[0];
  // not sure how to use this prio
  return aKey.priority - bKey.priority;
})
1
  • You can do something like this items.sort((a,b) => categories.find(e => e.name === b[0]).priority - categories.find(e => e.name === a[0]).priority) if you insist not to touch the data structures, but I would convert the lookup array into a set before. Commented Feb 3, 2022 at 14:05

4 Answers 4

3

You were very close, you just needed to grab b's priority (and also use the priority property). find rather than filter is a good choice:

const sorted = items.sort((a,b) => {
    const [aKey] = a;
    const [bKey] = b;
   
    const aPriority = categories.find(cat => cat.name === aKey).priority;
    const bPriority = categories.find(cat => cat.name === bKey).priority;
    return bPriority - aPriority;
});

Live Example

const items = [
    ["music", ["arr"]],
    ["movies", ["arr"]],
    ["quizes", ["arr"]],
    ["series", ["arr"]]
];

const categories = [
    { name: "music", priority: 3},
    { name: "movies", priority: 2},
    { name: "quizes", priority: 5},
    { name: "series", priority: 1},
    { name: "sports", priority: 4},
];

const sorted = items.sort((a,b) => {
    const [aKey] = a;
    const [bKey] = b;
   
    const aPriority = categories.find(cat => cat.name === aKey).priority;
    const bPriority = categories.find(cat => cat.name === bKey).priority;
    return bPriority - aPriority;
});
console.log(sorted);
.as-console-wrapper {
    max-height: 100% !important;
}

But repeatedly traversing that array of categories isn't a good idea if items is long. Instead, make a Map of key to priority, then use that:

const catPriorityMap = new Map(categories.map(({name, priority}) => [name, priority]));
const sorted = items.sort((a,b) => {
    const [aKey] = a;
    const [bKey] = b;
   
    const aPriority = catPriorityMap.get(aKey);
    const bPriority = catPriorityMap.get(bKey);
    return bPriority - aPriority;
});

Live Example

const items = [
    ["music", ["arr"]],
    ["movies", ["arr"]],
    ["quizes", ["arr"]],
    ["series", ["arr"]]
];

const categories = [
    { name: "music", priority: 3},
    { name: "movies", priority: 2},
    { name: "quizes", priority: 5},
    { name: "series", priority: 1},
    { name: "sports", priority: 4},
];

const catPriorityMap = new Map(categories.map(({name, priority}) => [name, priority]));
const sorted = items.sort((a,b) => {
    const [aKey] = a;
    const [bKey] = b;
   
    const aPriority = catPriorityMap.get(aKey);
    const bPriority = catPriorityMap.get(bKey);
    return bPriority - aPriority;
});
console.log(sorted);
.as-console-wrapper {
    max-height: 100% !important;
}

Lookup in a Map is done in sublinear time, whereas finding somethign in an array is done in linear time.

Sign up to request clarification or add additional context in comments.

Comments

3

You can use sort() method and check the priority from the categories

const items = [
  ['music', ['arr']],
  ['movies', ['arr']],
  ['quizes', ['arr']],
  ['series', ['arr']],
];

const categories = [
  { name: 'music', priority: 3 },
  { name: 'movies', priority: 2 },
  { name: 'quizes', priority: 5 },
  { name: 'series', priority: 1 },
  { name: 'sports', priority: 4 },
];

const result = items.sort(([a], [b]) => {
  const aPriority = categories.find(({ name }) => name === a).priority;
  const bPriority = categories.find(({ name }) => name === b).priority;
  return bPriority - aPriority;
});

console.log(result);

Learn more about sort() here.

1 Comment

Good answer, though some explanation would make it better. (Granted, there's only so much to say in this specific case! :-) )
2

You really do not want to use find() or filter() inside of the sort method because it is expensive. On every iteration, you are looking up the data in the array. So you are looping a lot. There is better ways to get the index.

Easiest thing is to make a lookup object so you are not having to search the other array over and over for a match. So if you can change categories to an object from the start, it will make your life so much easier.

In the sort I added max value in case the key is not defined. Now this would backfire if you had a value of zero since it is just a truthy check.

const items = [
  ['music', ['arr']],
  ['movies', ['arr']],
  ['quizes', ['arr']],
  ['series', ['arr']]
];

const categories = {
  music: 3,
  movies: 2,
  quizes: 5,
  series: 1,
  sports: 4,
};

items.sort(([keyA], [keyB]) => (categories[keyA] || Number.MAX_VALUE) - (categories[keyB] || Number.MAX_VALUE));

console.log(items);

If you can not make the object look like that and you have to use the array, you can convert it from the array to an object. That can be done a few ways. I like to use reduce.

const items = [
 ['music', ['arr']],
 ['movies', ['arr']],
 ['quizes', ['arr']],
 ['series', ['arr']]
];

const categories = [
 { name: "music", priority: 3},
 { name: "movies", priority: 2},
 { name: "quizes", priority: 5},
 { name: "series", priority: 1},
 { name: "sports", priority: 4},
];

const lookup = categories.reduce((acc, obj) => ({...acc, [obj.name]: obj.priority}), {});

items.sort(([keyA], [keyB]) =>  (lookup[keyA] || Number.MAX_VALUE) - (lookup[keyB] || Number.MAX_VALUE));

console.log(items);

Now if you are sure that all of the keys will exist in the categories, you can drop the max value

items.sort(([keyA], [keyB]) =>  lookup[keyA] - lookup[keyB];

Comments

1

You could take an object for the order and sort by delta.

const
    items = [['music', ['arr']], ['movies', ['arr']], ['quizes', ['arr']], ['series', ['arr']]],
    categories = [{ name: "music", priority: 3 }, { name: "movies", priority: 2 }, { name: "quizes", priority: 5 }, { name: "series", priority: 1 }, { name: "sports", priority: 4 }],
    order = Object.fromEntries(
        categories.map(({ name, priority }) => [name, priority])
    );

items.sort(([a], [b]) => order[a] - order[b]);

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.