My app makes a http call and returns an array of objects. I need to loop over the objects and insert in to a new array in alphabetical order. Problem is the last item in the newly created array is the only item out of order.
Example code: https://stackblitz.com/edit/typescript-zh16xc?file=package.json,index.ts
Aware i can use the native .sort(), however i am opting to forEach because i am performing more operations on each item, but the example has been trimmed down.
Code:
import { findIndex } from 'lodash';
let myList = [];
mockHttp()
.then((res: Array<any>) => {
console.log(res)
res.forEach(item => {
let index = findIndex(myList, function(listItem) {
return listItem.name.toLowerCase() > item.name.toLowerCase();
});
myList.splice(index, 0, {
name: item.name,
id: item.id,
enabled: false
})
})
console.log('result', myList);
});
function mockHttp() {
let p = new Promise(function(resolve,reject){
resolve([
{
id: 'dscjidovvocsi', name: 'Pear'
},
{
id: 'dscjidovvocsi', name: 'Banana'
},
{
id: 'dscjidovvocsi', name: 'Orange'
},
{
id: 'dscjidovvocsi', name: 'Blueberry'
},
{
id: 'dscjidovvocsi', name: 'Grapefruit'
},
{
id: 'dscjidovvocsi', name: 'Peach'
},
{
id: 'dscjidovvocsi', name: 'Strawberry'
},
{
id: 'dscjidovvocsi', name: 'Dragonfruit'
},
{
id: 'dscjidovvocsi', name: 'Mango'
},
{
id: 'dscjidovvocsi', name: 'Apples'
}
]);
});
return p;
}
The last item is: { enabled: false, id: "dscjidovvocsi", name: "Pear" }
Which is incorrect, all other items are ordered as expected.
findIndex
will return -1
if can't find a match.
When -1
is passed as an index to splice
, it inserts that in the second to last place, since negative indices count from the end, rather than the start.
const arr = [1,2,3]
arr.splice(-1, 0, 4)
console.log(arr) // [1,2,4,3]
So you can fix it by detecting that case and making sure to insert it at the end instead with:
if (index === -1) index = myList.length
For example:
mockHttp()
.then((res: Array<any>) => {
console.log(res)
res.forEach(item => {
let index = findIndex(myList, function(listItem) {
return listItem.name.toLowerCase() > item.name.toLowerCase();
});
if (index === -1) index = myList.length // added
myList.splice(index, 0, {
name: item.name,
id: item.id,
enabled: false
})
})
console.log('result', myList);
});
FYI: I debugged this with this snippet in the loop:
console.log('inserting', item.name, 'at index', index, 'into', myList.map(v => v.name))
Which made it pretty clear what was going on when it logged this: