搜索深度嵌套数组以更新对象

Search a deeply nested array to update an object

我有一个深度嵌套的数据结构,我有兴趣在我的数组(和数组数组)中匹配某个值,然后将一些数据推送到伴随的数组中。例如,下面是我的 colors 数组,伴随的是 moreColors 数组,它可能存在也可能不存在:

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

我有兴趣在我的数组中搜索颜色值 grey 并向该对象添加 moreColors 数组 moreColors: [{"color" : "blue"}] 。在某些情况下,如果数组已经存在,这可能会使用 push() 方法。我将如何最好地实现这一目标?我的目标是在这里添加值和 update/mutate myData 数组,因为这将传递给另一个函数。此处的嵌套可以有几层深,因此循环内的简单循环将无法工作。递归函数在这里最有效吗?我也愿意接受更好的方法或使用像 underscorelodash 这样的库。虽然我更喜欢香草 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"
                });
        }
    });
}

这是我认为您正在尝试的一个简单示例。

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

updateMoreColors() 接受上面返回的对象,如果不存在则先赋值 moreColors,然后推送到数组。

function findNestedColorObject(array, color) {
  let colorObject;

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

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

或者,由于您的尝试似乎是在同一个函数中进行搜索和更新,您可以将上述两个函数结合起来。 (这将继续更新所有匹配的对象,而不仅仅是第一个)。

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

对不起,有些深渊我是不会让自己沉下去的。我不会帮你做像改变原始数据这样野蛮的事情。

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

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 节点。

你好,检查一下我刚刚制作的这个函数,它真的很短,我认为它真的很好,我不知道什么是“递归”,但我在一个非常嵌套的对象数组上测试了它,我认为它也适用于对象看看输出:) 编辑:我找到了一个更好的方法,它不删除数据,而是 RETURNS 一个排序的 OBJ/OR 数组(你可以将其中一个传递给这个函数进行排序)请提供反馈

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)