尝试使用过滤器设置具有唯一值的数组失败

Posted

技术标签:

【中文标题】尝试使用过滤器设置具有唯一值的数组失败【英文标题】:Trying to set an array with unique values using filter is failing 【发布时间】:2021-06-27 02:53:34 【问题描述】:

我正在尝试合并 2 个数组,这些数组可能包含一些不同的键,从一个数组到另一个数组。

问题是它没有按应有的方式过滤已经合并的数组。我需要它具有独特的价值。

这是两个数组:

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,它们也必须针对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 数组中的项。

【问题讨论】:

【参考方案1】:

基本上,您似乎希望将第一个数组的所有内容复制到一个结果数组中,第二个数组中没有匹配的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;
  );
;

【讨论】:

【参考方案2】:

以下是实现所需输出的方法之一。

首先使用 arr1 中的 ids 创建一个地图 过滤arr2,其中在步骤1中创建的ids映射中不存在的对象的ID 在步骤 2 中连接 arr1filtered 数组

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;

【讨论】:

【参考方案3】:

您可以创建一个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]
)

【讨论】:

以上是关于尝试使用过滤器设置具有唯一值的数组失败的主要内容,如果未能解决你的问题,请参考以下文章

从数组中过滤对象,具有匹配两个值的差异

如何使用 Mongoose 查询过滤到数组类型字段中具有指定值的文档?

过滤和排序具有多个值的多维数组

Grafana Postgres 使用可具有多个值的 Where 查询时出错

过滤数组以具有唯一值[重复]

过滤的唯一索引导致更新失败,因为不正确的 'QUOTED_IDENTIFIER' 设置