搜索一个深嵌套的数组以更新对象

发布于 2025-01-25 18:25:10 字数 1286 浏览 2 评论 0原文

我有一个深度嵌套的数据结构,我有兴趣匹配数组中的某个值(和数组数组),然后在随附的数组中推动一些数据。 以下是我的颜色和伴随的数组

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

例如, 和添加morecolors数组的对象morecolors:[{“ color”:“ blue”}]。在某些情况下,如果数组已经存在,则可能使用 push()方法。我将如何最好地实现这一目标?我的目标是我想添加值并更新/突变 myData 数组,因为这将传递给另一个功能。这里的嵌套可以深度深,因此循环内部的简单循环无法正常工作。递归功能在这里效果最好吗?我也可以接受更好的方法或使用下划线 lodash 之类的库。尽管我更喜欢香草JS版本。下面是我启动的递归解决方案,但是该代码的运行不会超过深度。

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 accompanying array. For example following is my array of colors and accompanied 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"
                });
        }
    });
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

三生一梦 2025-02-01 18:25:10

这是我认为您正在尝试的快速示例。

findNestedColorObject()接受一个数组和一个颜色字符串来搜索并返回第一个color属性匹配的对象。

UpdateMoreColors()接受一个从上述返回的对象,并首先分配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);

或者,由于您的尝试似乎以相同功能搜索和更新,因此可以将上述两个功能组合在一起。 (这将继续更新匹配的所有对象,而不仅仅是第一个对象)。

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);

如评论中所述的编辑

我的第一个findNestedColorObject没有在成功搜索时退出循环。快速修复使用可能有更干净的解决方案。

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 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. (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. Quick fix applied though there is probably a cleaner solution.

素年丶 2025-02-01 18:25:10

抱歉,我不会让自己沉没的深度。我不会帮助您做一些如此野蛮的事情,例如突变您的原始数据。

但是,如果您对从旧结构中创建新结构的版本感兴趣,并且在其适当的位置具有附加的颜色节点,我们可以编写一个相当简单的递归:

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}

我们通过数组映射,保持颜色属性完好无损,然后以三种方式之一处理MoreColors

  • 如果color与我们的目标颜色匹配,我们会在morecolors 节点,并将其附加到我们的其他颜色。 (如果缺少此节点,我们将其默认为一个空数组。)
  • 如果没有,我们有现有的morecolor条目,我们会重新出现
  • ,如果我们没有任何内容,我们都会跳过morecolor完全节点。

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:

  • 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.
肩上的翅膀 2025-02-01 18:25:10

嗨,请检查我现在做出的这个功能,我真的很短,我认为它真的很好,我不知道什么是“递归”,但是我在带有对象的非常嵌套的数组上对此进行了测试,这也可以与对象一起使用,我认为看一下输出:)
编辑:我找到了一种没有删除数据但返回排序的OBJ/或数组的更好方法

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)

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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文