简体   繁体   English

搜索深度嵌套数组以更新 object

[英]Search a deeply nested array to update an object

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 accompanying array.我有一个深度嵌套的数据结构,我有兴趣在我的数组(和数组数组)中匹配某个值,然后将一些数据推送到伴随的数组中。 For example following is my array of colors and accompanied is a moreColors array which may or may not exist:例如,下面是我的colors数组,伴随的是一个可能存在也可能不存在的moreColors数组:

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"}] .我有兴趣在我的数组中搜索颜色值gray并向 object 添加 moreColors 数组moreColors: [{"color": "blue"}] In certain cases this might be using a push() method if the array already exists.在某些情况下,如果数组已经存在,这可能会使用push()方法。 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.我的目标是我想在这里添加值并更新/改变myData数组,因为这将传递给另一个 function。这里的嵌套可以有几层深,因此循环内的简单循环将不起作用。 Would a recursive function work best here?递归 function 在这里效果最好吗? I am also open to better methods or using libraries like underscore or lodash .我也愿意接受更好的方法或使用underscorelodash等库。 Although I'd prefer a vanilla js version.虽然我更喜欢香草 js 版本。 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"
                });
        }
    });
}

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. findNestedColorObject()接受一个数组和一个要搜索的颜色字符串,并返回color属性匹配的第一个 object。

updateMoreColors() accepts an object as returned from the above and first assigns moreColors if it doesn't exist, and then pushes to array. updateMoreColors()接受从上面返回的 object 并首先分配moreColors如果它不存在,然后推送到数组。

 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 commments 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 combine the two functions above.或者,由于您的尝试似乎是在同一个 function 中进行搜索和更新,因此您可以结合上面的两个功能。 (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 comments my first findNestedColorObject wasn't exiting the loop as it should on successful search.如评论中所述,我的第一个findNestedColorObject没有退出循环,因为它应该成功搜索。 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) // uncomment 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:我们 map 在数组上,保持颜色属性不变,然后以三种方式之一处理moreColors

  • if the color matches our target color, we recur on the moreColors node, and append to it our additional color.如果color与我们的目标颜色相匹配,我们将在moreColors节点上重复出现,并将 append 作为我们的附加颜色。 (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如果没有,并且我们有现有的moreColor条目,我们会重复使用它们
  • and if we don't have any, we skip the moreColor node altogether.如果没有,我们将完全跳过moreColor节点。

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嗨,检查一下这个 function 我刚刚制作的它真的很短我认为它真的很好我不知道什么是“递归”但是我在一个带有对象的非常嵌套的数组上测试了它并且这也适用于 object 我想看看 output :) 编辑:我找到了一个更好的方法,它不删除数据但返回一个排序的对象/或数组(你可以将其中一个传递给这个 function 进行排序)请提供反馈

 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM