I have just written a simple forEach loop two time and I was trying to look for a more optimal way to write this. I thought maybe I can filter directly and then return the result but again I will then have to run another loop for updating another object. So is there any optimal way to do this?
let shift = (
list: list[],
fileId: string,
folderId: string
): list[] => {
if (list.length > 0) {
let updatedList = list;
let fileToReplace: any = {};
let isAFile: number = 0;
let isAFolder: number = 0;
updatedList.forEach((item: list) => {
item.files.forEach((fileItem: {id: string, name: string}, index: number) => {
if (fileItem.id === fileId) {
fileToReplace = fileItem
item.files.splice(index, 1);
isAFile = isAFile + 1;
}
});
});
updatedList.forEach((item: list) => {
if (item.id === folderId) {
item.files.push(fileToReplace);
isAFolder = isAFolder + 1;
}
});
if (isAFile === 0) {
throw new Error('You cannot move a folder');
}
if (isAFolder === 0) {
throw new Error('You cannot specify a file as the destination');
}
return updatedList;
}
else {
throw new Error('This resource cannot be empty');
}
};
The time complexity cannot be improved as potentially all files need to be compared with the given identifier. But if you expect only one match (as your code is suggesting), then you could exit the loop when the match is found. You can also benefit from the .find and .findIndex methods.
I would also avoid naming a variable list, when list is also a name of a type.
For instance, here is some (untested) rewrite of your code:
let shift = (
resource: list[],
fileId: string,
folderId: string
): list[] => {
if (resource.length === 0) {
throw new Error('This resource cannot be empty');
}
let target: list | null = resource.find(({id}: {id: string}) => id === folderId);
if (target === null) {
throw new Error('The destination is not a folder in this resource');
}
for (let item: list of resource) {
let index: number = item.files.findIndex(({id}: {id: string}) => id === fileId);
if (index < 0) continue;
target.files.push(item.files.splice(index, 1)[0]);
return resource;
}
throw new Error('The item to move is not a file in this resource');
};