18

I have an object as shown:

const arr = [
  {
    name: 'FolderA',
    child: [
      {
        name: 'FolderB',
        child: [
          {
            name: 'FolderC0',
            child: [],
          },
          {
            name: 'FolderC1',
            child: [],
          },
        ],
      },
    ],
  },
  {
    name: 'FolderM',
    child: [],
  },
];

And I have path as string:

var path = "0-0-1".

I have to delete the object:

{
    name: 'FolderC1',
    child: [],
 },

Which I can do so by doing,

arr[0].child[0].splice(1, 1);

But I want to do it dynamically. Since path string can be anything, I want the above '.' operator and splice definition to be created dynamically to splice at particular place.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Uzair Khan
  • 2,812
  • 7
  • 30
  • 48
  • Have a look at [Convert JavaScript string in dot notation into a reference to the object](https://stackoverflow.com/q/6393943/1048572) – Bergi Dec 18 '18 at 20:51

5 Answers5

17

You could reduce the indices by saving the last index and returning the children of the actual index. Later splice with the last index.

function deepSplice(array, path) {
    var indices = path.split('-'),
        last = indices.pop();

    indices
        .reduce((a, i) => a[i].child, array)
        .splice(last, 1);
}

const array = [{ name: 'FolderA', child: [{ name: 'FolderB', child: [{ name: 'FolderC0', child: [] }, { name: 'FolderC1', child: [] }] }] }, { name: 'FolderM', child: [] }];

deepSplice(array, "0-0-1");
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
4

You could split your path and use the parts, like so:

let path = '0-0-1';
let parts = path.split('-');

// Call your splice using your parts (unsure if your '1' is the index, or deleteCount).

// If parts[2] is the index
arr[parts[0]].child[parts[1]].splice(parts[2], 1);

// If parts[2] is the deleteCount:
arr[parts[0]].child[parts[1]].splice(1, parts[2]);
Stuart
  • 6,630
  • 2
  • 24
  • 40
2

You could write a recursive function which travels down the hierarchy till the path is available. Below is a very minimal snippet.

const arr = [
  {
    name: 'FolderA',
    child: [
      {
        name: 'FolderB',
        child: [
          {
            name: 'FolderC0',
            child: [],
          },
          {
            name: 'FolderC1',
            child: [],
          },
        ],
      },
    ],
  },
  {
    name: 'FolderM',
    child: [],
  },
];

let ar_path = "0-0-1";

function deleteRecursive(arr, path) {
  if(Array.isArray(arr) && path.length > 0){
     const index = Number(path.shift());
     if (path.length > 0) 
        deleteRecursive(arr[index].child, path)
     else 
        arr.slice(index, 1);
  } else {
     console.log('invalid');
  }
}


deleteRecursive(arr, ar_path.split('-'))

console.log(arr);
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
0

If the path is always going to be composed by 3 (or less) indices you can do it easily like the following:

function deleteByPath(arr, path) {
   const index = path.split('-').map((x) => +x);
   if ( index.length < 1) {
      return null;
   } else if ( 1 === index.length ) {
     return arr.splice(index[0], 1);
   } else if ( 2 === index.length ) {
     return arr[index[0]].child.splice(index[1], 1);
   } else {
     return arr[index[0]].child[index[1]].child.splice(index[2], 1);
   }
}

const arr = [
  {
    name: 'FolderA',
    child: [
      {
        name: 'FolderB',
        child: [
          {
            name: 'FolderC0',
            child: [],
          },
          {
            name: 'FolderC1',
            child: [],
          },
        ],
      },
    ],
  },
  {
    name: 'FolderM',
    child: [],
  },
];

console.log(deleteByPath(arr, "0-0-1"));
console.log(deleteByPath(arr, "0-1"));
console.log(deleteByPath(arr, "0"));

If the path is going to be composed of maybe less than 3 parts you can adjust the function deleteByPath to handle cases based on number of parts.

if the path is going to be arbitrary and can have any length you can adjust the deleteByPath function to be recursive like the following:

function deleteByIndexRecursive(arr, index, current) {
  return current+1 < index.length ? deleteByIndexRecursive(arr.child[index[current]], current+1) : arr.child.splice(index[current], 1); 
}
function deleteByPath(arr, path) {
   const index = path.split('-').map((x) => +x);
   if ( 1>index.length) {
     return null;
   } else if ( 1===index.length) {
     return arr.splice(index[0], 1);
   } else {
     return deleteByIndexRecursive(arr[index[0]], index, 1);
   }
}
Nikos M.
  • 8,033
  • 4
  • 36
  • 43
0

//Variable setup:
const arr = [
    {
        name: 'FolderA',
        child: [
            {
                name: 'FolderB',
                child: [
                    {
                        name: 'FolderC0',
                        child: [],
                    },
                    {
                        name: 'FolderC1',
                        child: [],
                    },
                ],
            },
        ],
    },
    {
        name: 'FolderM',
        child: [],
    },
];
const path = "0-0-1";
//Break the path into pieces to iterate through:
const pathArray = path.split("-");
//Javascript assignments are by reference, so arrayToManage is going to be an internal piece within the original array
let arrayToManage = arr;
//We are going to iterate through the children of the array till we get above where we want to remove
while(pathArray.length > 1){
    const key = parseInt(pathArray.shift());
    arrayToManage = arrayToManage[key].child;
}
//Get the last position of the last array, where we want to remove the item
const key = parseInt(pathArray.shift());
arrayToManage.splice(key,1);
//And because it's all by reference, changed we made to arrayToManage were actually made on the arr object
console.log("end result:", JSON.stringify(arr));
Yishai Landau
  • 620
  • 4
  • 14