最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Search a deeply nested array to update an object - Stack Overflow

programmeradmin4浏览0评论

I have a deeply nested data structure and I am interested in matching a certain value inside my array (and array of arrays) and then pushing some data inside an acpanying array. For example following is my array of colors and acpanied is a moreColors array which may or may not exist :

var myData = [{
    "color": "green",
    "moreColors": [
        {
            "color": "beige"
        },
        {
            "color": "black",
            "moreColor": [
                {
                    "color": "grey"
                },
                {
                    "color": "white",
                    "moreColors": [...]
                }
            ]
        }
    ]
}]

I am interested in searching my array for the color value grey and to that object adding a moreColors array moreColors: [{"color" : "blue"}] . In certain cases this might be using a push() method if the array already exists. How would I best achieve this? My goal here is that I want to add values and update/mutate myData array here because this will be passed on to another function. The nesting here can be several levels deep so a simple loop inside a loop won't work. Would a recursive function work best here? I am also open to better methods or using libraries like underscore or lodash. Although I'd prefer a vanilla js version. Below is a recursive solution I started however, the code won't run more than a level deep.

findNested(myData, "grey")

function findNested(myArray, color) {
    myArray.moreColors?.forEach(element => {
        if(element.color !== color){
            if(element.moreColors.length > 0) {
                findNested(element.moreColors, color);
            }
        } else {
                element.moreColors.push({
                    "color": "blue"
                });
        }
    });
}

I have a deeply nested data structure and I am interested in matching a certain value inside my array (and array of arrays) and then pushing some data inside an acpanying array. For example following is my array of colors and acpanied is a moreColors array which may or may not exist :

var myData = [{
    "color": "green",
    "moreColors": [
        {
            "color": "beige"
        },
        {
            "color": "black",
            "moreColor": [
                {
                    "color": "grey"
                },
                {
                    "color": "white",
                    "moreColors": [...]
                }
            ]
        }
    ]
}]

I am interested in searching my array for the color value grey and to that object adding a moreColors array moreColors: [{"color" : "blue"}] . In certain cases this might be using a push() method if the array already exists. How would I best achieve this? My goal here is that I want to add values and update/mutate myData array here because this will be passed on to another function. The nesting here can be several levels deep so a simple loop inside a loop won't work. Would a recursive function work best here? I am also open to better methods or using libraries like underscore or lodash. Although I'd prefer a vanilla js version. Below is a recursive solution I started however, the code won't run more than a level deep.

findNested(myData, "grey")

function findNested(myArray, color) {
    myArray.moreColors?.forEach(element => {
        if(element.color !== color){
            if(element.moreColors.length > 0) {
                findNested(element.moreColors, color);
            }
        } else {
                element.moreColors.push({
                    "color": "blue"
                });
        }
    });
}

Share Improve this question edited May 3, 2022 at 8:02 Ara asked May 3, 2022 at 1:07 AraAra 631 silver badge6 bronze badges 5
  • Does this answer your question? Find all values by specific key in a deep nested object – pilchard Commented May 3, 2022 at 1:12
  • @pilchard The question on that page looks for all the ids and creates a new array, however I want to update my already existing myData array. So something maybe like forEach would be preferable as it updates the current array with the object pushed inside. – Ara Commented May 3, 2022 at 1:15
  • 1 What you do once you find the nested object is up to you and is straightforward, your primary question seemed to be about finding an arbitrarily deep object by key which the duplicate addresses (there are more duplicates if you search). – pilchard Commented May 3, 2022 at 1:19
  • My question however is more geared towards specifically updating my current array because I will be passing this to another function. – Ara Commented May 3, 2022 at 1:21
  • 1 Please share what you have attempted till now and what issue/s or error/s are faced. This may help other members to direct you towards a solution specific to your problem. – jsN00b Commented May 3, 2022 at 1:29
Add a ment  | 

3 Answers 3

Reset to default 4

Here is a quick example of what I think you are attempting.

findNestedColorObject() accepts an array of and a color string to search for and returns the first object whose color property matches.

updateMoreColors() accepts an object as returned from the above and first assigns moreColors if it doesn't exist, and then pushes to array.

function findNestedColorObject(array, color) {
  let colorObject;

  for (const obj of array) {
    if (obj.color === color) {
      colorObject = obj;
    } else if (obj.moreColors !== undefined) {
      colorObject = findNestedColorObject(obj.moreColors, color);
    }

    if (colorObject !== undefined) {
      break;
    }
  }

  return colorObject;
}

function updateMoreColors(colorObject, colors) {
  colorObject.moreColors ??= [];
  
  for (const color of [].concat(colors)) {
    colorObject.moreColors.push({ color });
  }
}

const myData = [{ "color": "green", "moreColors": [{ "color": "beige" }, { "color": "black", "moreColors": [{ "color": "grey" }, { "color": "white", "moreColors": ["ochre"] }] }] }];

const greyObject = findNestedColorObject(myData, 'grey');
console.log('found:')
console.log(greyObject);

updateMoreColors(greyObject, 'purple');
console.log('updated:');
console.log(greyObject);

const beigeObject = findNestedColorObject(myData, 'beige');
console.log('found:')
console.log(beigeObject);

updateMoreColors(beigeObject, ['salmon', 'crimson']);
console.log('updated:');
console.log(beigeObject);

// edit per the mments
const data = [{ color: "beige", moreColors: [{ color: "blue" }] }, { color: "black", moreColors: [{ color: "white" }] }];
const blue = findNestedColorObject(data, 'blue');
console.log('fixed overwrite error:')
console.log(blue);

Or, since your attempt seems to search and update in the same function you can bine the two functions above. (This will continue to update all objects which match, not just the first).

function updateNestedColorObject(array, color, moreColors) {
  for (const obj of array) {
    if (obj.color === color) {
      obj.moreColors ??= [];
      for (const color of [].concat(moreColors)) {
        obj.moreColors.push({ color });
      }
    }
    if (obj.moreColors !== undefined) {
      updateNestedColorObject(obj.moreColors, color, moreColors);
    }
  }
}

const myData = [{ "color": "green", "moreColors": [{ "color": "beige" }, { "color": "black", "moreColors": [{ "color": "grey" }, { "color": "white", "moreColors": ["ochre"] }] }] }];

updateNestedColorObject(myData, 'grey', 'purple');
updateNestedColorObject(myData, 'purple', 'beige');
updateNestedColorObject(myData, 'beige', ['salmon', 'crimson']);

console.log(myData);

Edit

As noted in the ments my first findNestedColorObject wasn't exiting the loop as it should on successful search. Quick fix applied though there is probably a cleaner solution.

Sorry, there are depths to which I will not let myself sink. I won't help you do something so barbaric as mutating your original data.

But if you're interested in a version that creates a new structure out of your old, with the additional color nodes in their proper place, we can write a reasonably simple recursion:

const addColor = (target, newColor) => (xs) =>
  xs .map (({color, moreColors = []}) => ({
    color,  
    ... (color == target
      ? {moreColors: addColor (target, newColor) (moreColors) .concat ({color: newColor})}
      : moreColors .length > 0
        ? {moreColors: addColor (target, newColor) (moreColors)} 
        : {}
    )
  }))

const myData = [{color: "green", moreColors: [{color: "beige"}, {color: "black", moreColors: [{color: "grey"}, {color: "white", moreColors: [{color: "..."}]}]}]}]

console .log (addColor ('grey', 'blue') (myData))
// console .log (myData) // unment to see that the original has not been folded, spindled, or mutilated
.as-console-wrapper {max-height: 100% !important; top: 0}

We map over the array, keeping the color property intact and then handling the moreColors in one of three ways:

  • if the color matches our target color, we recur on the moreColors node, and append to it our additional color. (If this node was missing, we've defaulted it to an empty array.)
  • if not, and we have existing moreColor entries, we recur on them
  • and if we don't have any, we skip the moreColor node altogether.

Hi check this function i made just now out its really short i think its really good i dont know what is a "recursion" but i tested this on a very nested array with objects and this also works with object i think take look at the output :) EDIT: I FOUND A BETTER WAY THAT DOESN'T DELETE THE DATA BUT RETURNS A SORTED OBJ/OR ARRAY (you can pass either into this function to be sorted) pls give feedback

var myData = [{
    "color": "green",
    "moreColors": [
        {
            "color": "blue"
        },
        {
            "color": "blue",
            "moreColor": [
                {
                    "color": "blue"
                },
                {
                    "color": "blue",
                    "moreColors": []
                }
            ]
        }
    ]
},['blue'],"blue"]
function searchArrOrObj(objOrArray,color,newColor) {
    let arrayOrObj = Object.assign((objOrArray.constructor===Array?[]:{}), objOrArray)
    for (item in arrayOrObj) {
        if (arrayOrObj[item]===color) {
            arrayOrObj[item] = newColor;
        } else if (typeof arrayOrObj[item]==='object') {
            arrayOrObj[item] = searchArrOrObj(arrayOrObj[item],color,newColor)
        }
    } 
    return arrayOrObj;
}
let newData = searchArrOrObj(myData,"blue","red")
console.log(myData)
console.log(newData)

发布评论

评论列表(0)

  1. 暂无评论