在 Node 中,如何将对象数组合并到一个新数组中,其中每个对象名称在字符串数组中都有其值?

In Node how to merge an array of objects into a new array where each object name has it's values in an array of strings?

提问人:DᴀʀᴛʜVᴀᴅᴇʀ 提问时间:11/8/2023 更新时间:11/8/2023 访问量:41

问:

我有一个对象数组,如下所示:

const arr = [
    {
        "name": "Day",
        "value": "Monday"
    },
    {
        "name": "Month",
        "value": "November"
    },
    {
        "name": "Day",
        "value": "Monday"
    },
    {
        "name": "Month",
        "value": "December"
    },
    {
        "name": "Day",
        "value": "Friday"
    },
    {
        "name": "Month",
        "value": "November"
    },
    {
        "name": "Day",
        "value": "Friday"
    },
    {
        "name": "Month",
        "value": "December"
    }
]

但我需要将我的对象数组修改为:

const final = [
    {
        "name": "Day",
        "values": [
            "Monday",
            "Friday"
        ]
    },
    {
        "name": "Month",
        "values": [
            "November",
            "December"
        ]
    }
]

我可以使用以下命令过滤掉重复项:

const filtered = arr.filter(
    (v, i, a) =>
      a.findIndex(v2 => v?.name === v2?.name && v?.value === v2?.value) === i
  );

但是我坚持在没有 Lodash下划线的情况下以有效的方式做到这一点,并且我尝试使用 Object.assign() 但我的实现不起作用:

const test = filtered.map(({ name, value }) =>
    Object.assign({ name, value: [] }, (name, value))
  );
console.log(test)

我以为我以前见过这个问题,并测试了以下答案:

在对象数组中,我可以将具有相同名称的对象组合在一起,但值在字符串数组中吗?

节点 .js 数组 javascript 对象

评论

0赞 Mike 'Pomax' Kamermans 11/8/2023
删除重复项后,您可能希望查看而不是 ,在迭代每个元素时构建一个新数组。尽管考虑到您的最终数据是什么样子,但我不确定数组是否是正确的选择。拥有一个带有 和 键的最终对象,每个都指向一个字符串数组,在下游代码中使用起来要容易得多。reducemapdaysmonths
0赞 DᴀʀᴛʜVᴀᴅᴇʀ 11/8/2023
问题是问题的最终结果是下游的预期是什么,或者我会做你提到的方法。
0赞 Mike 'Pomax' Kamermans 11/8/2023
然后会把你带到那里,并有助于消除过滤任何东西的需要。reduceSet

答:

0赞 Mike 'Pomax' Kamermans 11/8/2023 #1

reduce 与预先分配的 days 和 moths 元素的起始值一起使用,使用 Set 自动忽略重复项,然后在减少所有内容后,将该集合转换为数组:

const arr = [{
    name: "Day",
    value: "Monday",
  },{
    name: "Month",
    value: "November",
  },{
    name: "Day",
    value: "Monday",
  },{
    name: "Month",
    value: "December",
  },{
    name: "Day",
    value: "Friday",
  },{
    name: "Month",
    value: "November",
  },{
    name: "Day",
    value: "Friday",
  },{
    name: "Month",
    value: "December",
}];

// reduce the data to the form you need:
const final = arr.reduce(
  (resultSoFar, {name, value}) => {
    // find the "bin" to add this value to:
    let bin = resultSoFar.find((e) => e.name === name);
    // or make a new bin if there isn't one:
    if (!bin) resultSoFar.push(bin = { name, values: new Set() });
    // then add our value, and return the new result so far.
    bin.values.add(value);
    return resultSoFar;
  },
  // and start with `resultSoFar` being an empty array:
  []
);

// as last step, convert the sets into plain arrays:
final.forEach(e => e.values = [...e.values]);

// what did we get?
console.log(final);

评论

0赞 DᴀʀᴛʜVᴀᴅᴇʀ 11/8/2023
这既有效又有趣的方法,可以研究它并了解更多信息。认为我对什么是有点困惑.reduceresultSoFar
0赞 DᴀʀᴛʜVᴀᴅᴇʀ 11/8/2023
如果我正确理解了该方法,也可以将其修改为不必在管道中向下转换?与其他方法相比,是否有理由实施?new SetforEachnew Set()
0赞 DᴀʀᴛʜVᴀᴅᴇʀ 11/8/2023
啊,我从最近的评论中看到,消除了过滤的需要。new Set
1赞 Mike 'Pomax' Kamermans 11/8/2023
你说你为你显示的形式是你特别需要的,所以forEach只是硬转换为一个,因为集合没有“有”索引,也不支持括号表示法。const finalSetArray
1赞 Mike 'Pomax' Kamermans 11/8/2023
至于 ,这是 的关键方面:它从您指定为 reduce 调用的第二个参数的任何内容开始,在每个迭代步骤中,您的返回值成为下一个迭代步骤的 ,最后一个迭代步骤的返回值是它本身返回的内容。resultSoFarreduceresultSoFarreduce