Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I sort an array of objects based on another array of objects

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 ...}
]
like image 782
user7659932 Avatar asked Oct 26 '25 06:10

user7659932


1 Answers

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);
like image 131
p.s.w.g Avatar answered Oct 28 '25 18:10

p.s.w.g