Reputation: 59
I'm trying to sort an array of objects by array of keys. I searched through similar questions but I didn't find anything that could help me
Example:
const data = [
{ label: 'String'},
{ label: 'Number'},
{ label: 'Boolean'},
{ label: 'Array'}
]
const order = [2, 3]
Expected result:
const data = [
{ label: 'Boolean'},
{ label: 'Array'},
{ label: 'String'},
{ label: 'Number'}
]
The problems that I'm facing are
order
array can have or can not have the same length like data
, the items key that not exists in order
must go to the bottomdata
objects has not an order key to help sort the element, the ordering will made by array object key positionWhat I tried but not working
data.sort((a, b) => {
const aIndex = data.indexOf(a);
const bIndex = data.indexOf(b);
if(aIndex !== -1) return -1;
if(bIndex !== -1) return 1;
return order.indexOf(aIndex) - order.indexOf(bIndex);
})
Upvotes: 5
Views: 194
Reputation: 28196
I really like @n--'s approach. However, it will run into difficulties if a certain value appears multiple times in the array. These problems can be overcome very easily when we build the Set
with indexes instead of values of data
:
const data = [
{ label: 'String'},
{ label: 'Number'},
{ label: 'Boolean'},
{ label: 'Array'},
{ label: 'String'}
];
const order = [2, 3];
const out = [...new Set([...order,...data.keys()])].map(i=>data[i]);
console.log(out);
Upvotes: 1
Reputation: 11347
Extract elements from order
and then add those not in order
:
const data = [
{ label: 'String'},
{ label: 'Number'},
{ label: 'Boolean'},
{ label: 'Array'}
]
const order = [2, 3]
result = [
...order.map(i => data[i]),
...data.filter((_, i) => !order.includes(i)),
]
console.log(result)
Upvotes: 1
Reputation: 3856
You can just use a Set to map the data as you need, like this:
const data = [
{ label: 'String'},
{ label: 'Number'},
{ label: 'Boolean'},
{ label: 'Array'}
]
const order = [2, 3];
const out = [...new Set([...order.map(i => data[i]), ...data])];
console.log(out);
Upvotes: 4
Reputation: 72226
Instead of doing a sort, implement a straight-forward algorithm in two steps:
order
list and extract the corresponding items of data
into a new list (the sorted list). Replace the extracted values with undefined
in data
.data
and append each item that is not undefined
to the sorted list.const data = [
{ label: 'Test 3'},
{ label: 'Test 4'},
{ label: 'Test 1'},
{ label: 'Test 2'}
];
const order = [2, 3, 1, 5];
// Create a working copy of `data` (to not modify `data`)
const work = [...data];
// The sorted list
const sorted = [];
// Step 1
// Run through `order` and move the items from `work` to `sorted` in the provided order
order.forEach((index) => {
const item = data[index];
// There is nothing to do if `index` is an invalid index (or `data` does not contain anything at that position)
if (item !== undefined) {
sorted.push(item);
work[index] = undefined;
}
});
// Step 2
// Move the remaining items (they are not mentioned in `order`)
work.forEach((item) => {
// Ignore the items that were moved on the first step
if (item !== undefined) {
sorted.push(item);
}
});
// Cleanup
delete work;
// Check the output visually
console.log(sorted);
Upvotes: 1