I have an array of a dynamic sizing that changes its order based on what is last selected to position 0 of the array. Problem is I want to keep the original order of the array.
In order to do that, I have created an additional variable that is set to the original sorting of the array. Although some of the values of the array might change after the selecting of the item, the name property never does. I want to use this fact to sort the new array to the original position.
let keepRateOrder = rates.sort((a, b) => {
return prevRates.indexOf(a.name) - prevRates.indexOf(b.name);
});
const rates = [
{name:'UPS', isChoosen:true, cost:63 ...},
{name:'Mail', isChoosen:false, cost:23 ...},
{name:'FedEx', isChoosen:false, cost:33 ...}
]
const prevRates = [
{name:'Mail', isChoosen:false, cost:23 ...},
{name:'UPS', isChoosen:true, cost:63 ...},
{name:'FedEx', isChoosen:false, cost:33 ...}
]
3 Answers 3
This can be solved using findIndex
. In the following example the sort will put Mail
first as per the prevRates
array:
const rates = [
{name:'UPS', isChoosen:true, cost:63},
{name:'Mail', isChoosen:false, cost:23},
{name:'FedEx', isChoosen:false, cost:33}
];
const prevRates = [
{name: 'Mail'},
{name: 'UPS'},
{name: 'FedEx'},
];
let keepRateOrder = rates.sort((a, b) => {
return prevRates.findIndex(p => p.name === a.name) - prevRates.findIndex(p => p.name === b.name);
});
console.log(keepRateOrder);
You could accomplish the same thing with indexOf
if you map
first. This leads to somewhat cleaner code:
const rates = [
{name:'UPS', isChoosen:true, cost:63},
{name:'Mail', isChoosen:false, cost:23},
{name:'FedEx', isChoosen:false, cost:33}
];
const prevRates = [
{name: 'Mail'},
{name: 'UPS'},
{name: 'FedEx'},
].map(x => x.name);
let keepRateOrder = rates.sort((a, b) => {
return prevRates.indexOf(a.name) - prevRates.indexOf(b.name);
});
console.log(keepRateOrder);
And here's one more solution just using a hash of the original indexes, created using reduceRight
:
const rates = [
{name:'UPS', isChoosen:true, cost:63},
{name:'Mail', isChoosen:false, cost:23},
{name:'FedEx', isChoosen:false, cost:33}
]
const prevRates = [
{name: 'Mail'},
{name: 'UPS'},
{name: 'FedEx'},
].reduceRight((a, x, i) => (a[x.name] = i, a), {});
let keepRateOrder = rates.sort((a, b) => {
return prevRates[a.name] - prevRates[b.name];
});
console.log(keepRateOrder);
Since you said that items may be added or removed from the original array, note that all of the above solutions will place new items first (since their index in the prevRates
array will be returned as -1
). If you want new items to appear at the end, you'll need to do something like this:
const rates = [
{name:'UPS', isChoosen:true, cost:63},
{name:'Mail', isChoosen:false, cost:23},
{name:'Foo'},
{name:'FedEx', isChoosen:false, cost:33},
];
const prevRates = [
{name: 'Mail'},
{name: 'UPS'},
{name: 'FedEx'},
].map(x => x.name);
let keepRateOrder = rates.sort((a, b) => {
const aIndex = prevRates.indexOf(a.name);
const bIndex = prevRates.indexOf(b.name);
return (aIndex === -1 ? Number.MAX_VALUE : aIndex) - (bIndex === -1 ? Number.MAX_VALUE : bIndex);
});
console.log(keepRateOrder);
First use .map
to transform the prevRates
into an array of just the name
properties, and then you can use .sort
based on that array of names:
const prevRates = [
{name:'Mail', isChoosen:false, cost:23 },
{name:'UPS', isChoosen:true, cost:63 },
{name:'FedEx', isChoosen:false, cost:33 }
];
const rates = [
{name:'UPS', isChoosen:true, cost:63 },
{name:'Mail', isChoosen:false, cost:23 },
{name:'FedEx', isChoosen:false, cost:33 }
];
const prevRatesNames = prevRates.map(({ name }) => name);
rates.sort((a, b) => (
prevRatesNames.indexOf(a.name) - prevRatesNames.indexOf(b.name)
));
console.log(rates);
Remember that .sort
sorts in-place - if you do
let keepRateOrder = rates.sort...
then keepRateOrder
will just be another reference to the rates
array. If you want a copy, rather than mutating the original rates
array, then you'll have to shallow copy rates
first:
const keepRateOrder = rates.slice().sort...
How about adding a new property to each item to track the original index, originalIndex
. Sort using that when you want the original order back, avoids the extra copy. Assuming that's what you want to do!
name
?