0

I have two arrays, one containings some items, and another containings sorted ids of those items like so:

const items = [
    { id: 1, label: 'foo' },
    { id: 2, label: 'bar' },
    { id: 3, label: 'lorem' },
    { id: 4, label: 'ipsum' },
]

const sortedItemIds = [4, 3, 2, 1]

I want to have another array containing items sorted by their id like so:

const sortedItems = [
    { id: 4, label: 'ipsum' },
    { id: 3, label: 'lorem' },
    { id: 2, label: 'bar' },
    { id: 1, label: 'foo' },
]

Note that the order may not be whatever, not asc or desc

I made this piece of code, that works pretty well as it:

let sortedItems = []
sortedItemIds.map((itemId, index) => {
    items.map(item) => {
        if (item.id === itemId) {
            sortedItems[index] = item
        }
    }
})

I feel like I may run into issues with a large array of items, due to the nested Array.map() functions

Is there a better way / best practice for this scenario?

pistou
  • 2,799
  • 5
  • 33
  • 60
  • 3
    None of the `.map()` calls return anything, hence they are not the right tool for the task – Andreas Oct 01 '18 at 16:59
  • Possible duplicate of [Javascript - sort array based on another array](https://stackoverflow.com/questions/13304543/javascript-sort-array-based-on-another-array) – Andreas Oct 01 '18 at 17:00

2 Answers2

3

You could create one object where keys are ids and then use that object get values by id.

const items = [{ id: 1, label: 'foo' },{ id: 2, label: 'bar' },{ id: 3, label: 'lorem' },{ id: 4, label: 'ipsum' }]
const sortedItemIds = [4, 3, 2, 1]

const obj = {}
items.forEach(o => obj[o.id] = o);

const sortedItems = sortedItemIds.map(e => Object.assign({}, obj[e]));
console.log(sortedItems)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • 1
    The `Object.assign({}, ...)` seems unnecessary here. OP has not mentioned any requirement about performing a shallow clone of each of the objects and in any case the use of `Object.assign()` should at least have a brief explanation. – Patrick Roberts Oct 01 '18 at 17:06
  • What if the item's `id` is not an Int, but let's say a String? And in case of *mixed* types? – pistou Oct 01 '18 at 17:15
  • Nevermind I didn't understand your code. Seems pretty good to me now! – pistou Oct 01 '18 at 17:16
1

You don't need the function map for doing this, just use the find Array.indexOf and Array.sort in order to sort it.

const items = [{ id: 1, label: 'foo' },{ id: 2, label: 'bar' },{ id: 3, label: 'lorem' },{ id: 4, label: 'ipsum' }],
      sortedItemIds = [4, 3, 2, 1];

items.sort((a, b) => sortedItemIds.indexOf(a.id) - sortedItemIds.indexOf(b.id));
console.log(items);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ele
  • 33,468
  • 7
  • 37
  • 75
  • Looks like this solution works well. I modified it for my needs, adding `.slice()` as I didn't want to change my first array. `const sortedItems = items.slice().sort((a, b) => sortedItemIds.indexOf(a.id) - sortedItemIds.indexOf(b.id));`. – pistou Oct 01 '18 at 17:08
  • 1
    The efficiency of this is O(n^2 log n), whereas @NenadVracar's answer is ~O(n) assuming approximately constant time for key lookup. Not exactly an optimized implementation. – Patrick Roberts Oct 01 '18 at 17:09