Reputation:
I have an array of objects being returned from an API.
let arr = [
{name: 'Blur'},
{name: 'The Beatles'},
{name: 'Oasis'},
{name: 'Arctic Monkeys'},
{name: 'Elvis'}
];
I always want Arctic Monkeys
to come one before Oasis
and leave the other items as they are. Sometimes the API will return them in the correct order, but in some instances they will be the wrong way around like the above.
Can anyone advise of the best way to do this?
I know I can do something like this but feel there must be a better way.
for(let i = 0; i < arr.length; i++){
if(arr[i].name == 'Arctic Monkeys' && arr[i - 1].name === 'Oasis' ){
let oasisObj = arr[i];
arr[i - 1] = arr[i];
arr[i] = oasisObj;
}
}
Or perhaps I should not mutate this array and create a whole new array ?
Upvotes: 1
Views: 2256
Reputation: 8170
Here's a function which takes an array, and two names of the items within that array. It then ensures that the 1st named item appears directly before the 2nd named item!
var ensureAbove = function(arr, above, below) {
// Find the indices of the above and below items
var aboveInd = -1;
var belowInd = -1;
for (var i = 0; i < arr.length; i++) {
if (arr[i].name === above) aboveInd = i;
if (arr[i].name === below) belowInd = i;
// If we've found both indices we can stop looking
if (aboveInd > -1 && belowInd > -1) break;
}
// Now ensure that the item at index `aboveInd` comes before
// index `belowInd`
var loInd = Math.min(belowInd, aboveInd);
var hiInd = Math.max(belowInd, aboveInd);
// All the items before `aboveInd` and `belowInd`
var itemsBefore = arr.slice(0, loInd);
// All the items after both `aboveInd` and `belowInd`
var itemsAfter = arr.slice(hiInd + 1);
// All the items between `aboveInd` and `belowInd`
var itemsBetween = arr.slice(loInd + 1, hiInd);
/*
Ok here's the tactical bit. We can definitely add all the
`itemsBefore` as the very first thing, and we can definitely
add all the `itemsAfter` as the very last thing. This middle
is trickier - we either want to add the above and below items and then
the middle items, OR we add the middle items first and then the above or
below items.
*/
var result = itemsBefore;
if (belowInd < aboveInd) {
result.push(arr[aboveInd]);
result.push(arr[belowInd]);
}
result = result.concat(itemsBetween);
if (belowInd > aboveInd) {
result.push(arr[aboveInd]);
result.push(arr[belowInd]);
}
result = result.concat(itemsAfter);
return result;
};
Now apply this code to your array:
let arr = [
{name: 'Blur'},
{name: 'The Beatles'},
{name: 'Oasis'},
{name: 'Arctic Monkeys'},
{name: 'Elvis'}
];
let orderedArr = ensureAbove(arr, 'Arctic Monkeys', 'Oasis');
Note that depending on your situation, it may be more efficient to fix your api.
Upvotes: 1
Reputation: 31712
let arr = [
{name: 'Blur'},
{name: 'The Beatles'},
{name: 'Oasis'},
{name: 'Elvis'},
{name: 'Arctic Monkeys'},
];
// First: look for their indexes
let oasis = -1, monkey = -1; // assuming the indexes are -1
for(let i = 0; i < arr.length && (oasis === -1 || monkey === -1); i++) { // the loop will end when they're both found or the end of the array is reached
if(arr[i].name === "Arctic Monkeys") monkey = i; // if this elemenet is the monkey then assign the current index i to monkey
else if(arr[i].name === "Oasis") oasis = i; // ... same for oasis
}
// Second: if they're not in the right order, change the position of monkey
if(oasis !== -1 && monkey !== -1 && monkey !== oasis - 1) { // if we found them both and if monkey isn't right before oasis, then
monkey = arr.splice(monkey, 1) [0]; // cut monkey out (using splice 1)
arr.splice(oasis, 0, monkey); // insert it right before oasis (using splice 0 monkey)
}
console.log(arr);
Upvotes: 1
Reputation: 386776
You could use an object and check if both names are in the object.
But Array#sort
might no produce stable results, depending on the implemented sort algorithm.
let arr = [{ name: 'Blur' }, { name: 'The Beatles' }, { name: 'Oasis' }, { name: 'Arctic Monkeys' }, { name: 'Elvis' }],
order = { 'Arctic Monkeys': 1, Oasis: 2 };
arr.sort((a, b) => (b.name in order) && (a.name in order) ? order[a.name] - order[b.name] : 0);
console.log(arr);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 0
Reputation: 4180
The best way I believe is to adjust this on the server side with some specific sorting rule. To just fix the specific scenario on the client you might do.
let arr = [
{name: 'Blur'},
{name: 'The Beatles'},
{name: 'Oasis'},
{name: 'Arctic Monkeys'},
{name: 'Elvis'}
]
console.log(arr.map(o => o.name))
let iO = arr.findIndex(o => o.name === 'Oasis')
let iA = arr.findIndex(o => o.name === 'Arctic Monkeys')
if ((iA !== -1 && iO !== -1) && iA > iO) {
let o = arr[iO]
let a = arr[iA]
arr[iO] = a
arr[iA] = o
}
console.log(arr.map(o => o.name))
Upvotes: 0