使用filter设置具有唯一值的数组失败了。

3

我正在尝试合并两个数组,这两个数组可能包含不同的键。

问题在于它没有像应该那样过滤已合并的数组。我需要保证它的值是唯一的。

这是两个数组:

const arr1 = [
  {
    id: "1",
    title: "My Name"
  },
  {
    id: "2",
    title: "Your Name"
  },
  {
    group: [
      {
        id: "4",
        title: "Some Agreement"
      },
      {
        id: "5",
        title: "Some Beer"
      }
    ]
  }
];

const arr2 = [
  {
    id: "1",
    title: "Company Name",
  },
  {
    id: "2",
    title: "A title",
  },
  {
    id: "3",
    title: "Question Group 1",
  },
  {
    id: "4",
    title: "Confidentiality Agreement",
  },
  {
    id: "5",
    title: "Some more",
  },
  {
    id: "6",
    title: "Ayo",
  }
];

第一个数组有时可能会包含名为group的键,它是与核心数组中对象({ id: string, title: string })类型相同的2个或更多项的混合。

第一个数组由第二个数组中的项目组成。

现在我需要将arr2的所有项目发送到arr1,而不从arr2中删除这些项目,但我需要从该合并中排除已有的项目/ ID,这些已有项目/ ID 还必须与group键/数组中的项目进行测试。 你懂吗?

这应该是arr1的最终结果:

const arr1 = [
  {
    id: "1",
    title: "My Name"
  },
  {
    id: "2",
    title: "Your Name"
  },
  {
    group: [
      {
        id: "4",
        title: "Some Agreement"
      },
      {
        id: "5",
        title: "Some Beer"
      }
    ]
  },
  {
    id: "3",
    title: "Question Group 1",
  },
  {
    id: "6",
    title: "Ayo",
  }
]

如您所见,新项目必须添加到数组的末尾,位置应该保持不变。

我创建了一个可重现的示例:https://codesandbox.io/s/determined-beaver-r5t6v?file=/src/App.js

相关的代码片段:

  const handleClick = () => {
    setMerge((qs) => {
      const merged = [...qs, ...qs2];

      const unique = merged.filter((v, i, a) => {
        return v.id === a[i].id;
      });

      return unique;
    });
  };

我到了这一步,因为我甚至无法根据id将数组按独特的值进行过滤。

问题在于这个函数可以有不同的开发方式。我只需要在arr2中不允许重复项,包括"group"数组中的项。

3个回答

2
以下是实现所需输出的其中一种方法:
  • 首先创建一个包含在arr1中存在的id的Map
  • 筛选arr2,其中对象的id不存在于步骤1中创建的ids Map中
  • 将arr1和步骤2中筛选出来的filtered数组连接起来

const arr1 = [{id:"1",title:"My Name"},{id:"2",title:"Your Name"},{group:[{id:"4",title:"Some Agreement"},{id:"5",title:"Some Beer"}]}];

const arr2 = [{id:"1",title:"Company Name"},{id:"2",title:"A title"},{id:"3",title:"Question Group 1"},{id:"4",title:"Confidentiality Agreement"},{id:"5",title:"Some more"},{id:"6",title:"Ayo"}];

//Create a Map with ids which are present in arr1
const ids = arr1.reduce((res, obj) => {
  if(obj.group) {
    obj.group.forEach(innerObj => {
      res[innerObj.id] = innerObj
    });
  } else {
    res[obj.id] = obj;
  }
  return res;
}, {});
//console.log(ids);

//Filter out the arr2 where the id of an object is not
//present in the Map created above(i.e., ids object)
const filteredItems = arr2.filter(({id}) => !ids[id]);
//console.log(filteredItems);

//Concatenate arr1 and the filteredItems to get the final output
const finalRes = [...arr1, ...filteredItems];
console.log(finalRes);
.as-console-wrapper {
  max-height: 100% !important;
}


2
基本上,您希望将第一个数组的所有内容复制到结果数组中,并且只将第二个数组中那些在第一个数组中没有匹配的“id”的内容复制到结果数组中。
此解决方案在“group”属性数组上使用递归搜索,递归基本情况仅检查“id”属性。
const isContained = (arr, element) => arr.some(el => {
  if (el.group) {
    return isContained(el.group, element); // <-- recurse on group array
  }
  return el.id === element.id // <-- return ids match
});

...

const handleClick = () => {
  setMerge((qs) => {
    const merged = [
      ...qs, // <-- shallow copy first array
      ...qs2.filter((el) => !isContained(qs, el)), // <-- filtered second array
    ];

    return merged;
  });
};

Edit trying-to-set-an-array-with-unique-values-using-filter-is-failing


2

您可以创建一个Set来追踪arr1中已存在的id,并且只添加在arr2中不存在于arr1中的项。

setMerge((qs) => {
  const ids = new Set()
  qs.forEach((item) => {
    if (item.group) {
      item.group.forEach((el) => ids.add(el.id))
      return
    }
    ids.add(item.id)
  })

  const itemsToAdd = qs2.filter((item) => !ids.has(item.id))
  return [...qs, ...itemsToAdd]
})

Edit hungry-forest-1fybc


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接