websterz websterz - 3 months ago 23
Javascript Question

Deleting data from multi dimensional array

I have following multi dimensional object array:

var data ='{
"Form": [],
"Report": [],
"Misc": [],
"Test5": [],
"Test4": [],
"Provider": [
{ "Memorial Hospital": ["img0.jpg"] },
{ "Cooper Memorial Hospital": [
"img1.jpg",
{ "Emergency Reports": ["img2.jpg"] },
{ "Diagnostic Reports": [
"img3.jpg",
{
"12/12/2006": ["img4.jpg", "img5.jpg"],
"03/13/2009": ["img6.jpg", "img7.jpg"]
}
]},
{ "Accident Reports": ["img8.jpg"] },
{ "Other Reports": ["img9.jpg", "img10.jpg"] }
]}
]
}';


I want to remove data from the array its
img7.jpg
under
"03/13/2009"


What I do is:

var obj = JSON.parse(data);
console.log(obj['Provider'][1]["Cooper Memorial Hospital"][2]["Diagnostic reports"][0]["12/12/2006"]).splice(0,1);


That is all working, now issue arises when I add/remove arrays from "Cooper Memorial Hospital". Index gets recounted.

So I want to splice with out index, is there any way I can remove the img from the arrays and sub arrays just calling by img3.jpg:

removeImg("img3.jpg", obj['Provider']);


Something like this.

Update:
I tried with this code, but it requires some additional code for looping through the sub arrays:

function remove(arr, what) {
var found = arr.indexOf(what);
while (found !== -1) {
arr.splice(found, 1);
found = arr.indexOf(what);
if(found)
break;
}
}

remove(a,"img1");

Answer

My first instinct is to try and fix this server side, because the data-format looks a bit weirdly nested.

To fix it client side, you'll need to write a recursive function that checks all nested arrays for the string and deletes it on the go.

First, the code to remove an item from an array:

 var removeStringFromArray = function(str, array) {
  var index = array.indexOf(str);
  if (index !== -1) {
    array.splice(index, 1);
  }
};

This dynamically looks up the index of the string and splices it. Note that this mutates your array.

To look through all items in an object, we'll use this snippet:

Object.keys(obj).forEach(function(key) {
  var value = obj[key];
  // Do something with value...
});

This gets an array of keys and loops its values. If these two snippets look okay to you, you can combine them in a recursive function like I did in the example below. I haven't optimized for performance or lines of code; I tried to make it readable. Also note that I'm using Array.isArray and a quick-and-dirty isPrimitive check.

var removeStringFromArray = function(str, array) {
  var index = array.indexOf(str);
  if (index !== -1) {
    array.splice(index, 1);
  }
};

var removeStringFromArraysInVariable = function(str, val) {
    if (isPrimitive(val)) {
      // Don't do anything for falsy, bools, strings, numbers
      return;
    }
    
    // For an array
    if (Array.isArray(val)) {
      // Remove all strings first
      removeStringFromArray(str, val); 
      
      // Call method recursively for any non string values that might be there
      val.forEach(function(innerVal) {
      	removeStringFromArraysInVariable(str, innerVal);
      });
      return;
    }
    
    // If we get here, it's probably an object
    Object.keys(val).forEach(function(key) {
      // Call recursively for each property value
      removeStringFromArraysInVariable(str, val[key]);
    });
};

// You might want to look up if this is a fool proof way to check for primitives
var isPrimitive = function(val) {
  if (!val) return true;
  
  var constr = (val).constructor;
  return (
    constr === Number ||
    constr === Boolean ||
    constr === String);
}  


// Test data
var data = {
  "Form": [],
  "Report": [],
  "Misc": [],
  "Test5": [],
  "Test4": [],
  "Provider": [{
    "Memorial Hospital": ["img0.jpg"]
  }, {
    "Cooper Memorial Hospital": [
      "img1.jpg", {
        "Emergency Reports": ["img2.jpg"]
      }, {
        "Diagnostic Reports": [
          "img3.jpg", {
            "12/12/2006": ["img4.jpg", "img5.jpg"],
            "03/13/2009": ["img6.jpg", "img7.jpg"]
          }
        ]
      }, {
        "Accident Reports": ["img8.jpg"]
      }, {
        "Other Reports": ["img9.jpg", "img10.jpg"]
      }
    ]
  }]
};

removeStringFromArraysInVariable("img3.jpg", data);
console.log(data);