【问题标题】:Getting exact Matching elements between two arrays获取两个数组之间的精确匹配元素
【发布时间】:2020-02-23 01:44:00
【问题描述】:

我有两个数组如下:

array1 = [
         {id:1, children: ['a', 'b']},
         {id:2, children: ['a', 'b']},
         {id:3, children: ['b', 'c']},
         {id:4, children: ['c', 'a']},
         {id:5, children: ['a', 'b', 'c']}];

array2 = ['a', 'b'];

现在我想在 JS/TS 中编写一个代码,它将从 array1 中找到确切的对象,其中数组 2 中的子数组的每个元素都与数组 1 中的子数组的每个元素完全匹配(顺序无关紧要)。

我试图用三个过滤器来解决这个问题,附加条件是数组 1 和数组 2 之间的子数组长度匹配。但是,如果这些子数组中至少有一个元素与所需的数组长度相匹配,这也会出现。

如果有人给我解决方案,我将不胜感激。

array1
.filter(a => a.children
.filter(b => array2
.filter(c => b === c)).length === array2.length);

编辑:

我实际上在上面的例子中稍微简化了这个问题。在我的实际项目中,这两个数组如下:

 const productOrders: ProductOrder[] =
      [
        {
          productId: 1, subProductOrders:
            [{subProduct: {subProductId: 1}}, {subProduct: 
{subProductId: 2}}]
        },
        {
          productId: 1, subProductOrders:
            [{subProduct: {subProductId: 2}}, {subProduct: 
{subProductId: 1}}]
        },
        {
          productId: 1, subProductOrders:
            [{subProduct: {subProductId: 2}}, {subProduct: 
{subProductId: 3}}]
        },
        {
          productId: 1, subProductOrders:
            [{subProduct: {subProductId: 1}}, {subProduct: 
{subProductId: 2}}, {subProduct: {subProductId: 3}}]
        },
      ];

    const matchingCriteria: SubProductOrder[] =
      [
        [{subProduct: {subProductId: 1}}, {subProduct: {subProductId: 
2}}]

      ];

现在我想从 productOrders 数组中查找产品,其中 subProductOrders 数组的 subProductId 与 matchingCriteria 数组的 subProductId 匹配(顺序无关紧要)。在上面的例子中,productOrders 数组的前两个产品应该匹配,尽管 subProductsIds 是无序的

【问题讨论】:

标签: javascript arrays typescript


【解决方案1】:

您可以在单个过滤器中使用Array#every() 和长度

const arr1 = [
   {id:1, children: ['a', 'b']},
   {id:2, children: ['a', 'b']},
   {id:3, children: ['b', 'c']},
   {id:4, children: ['c', 'a']},
   {id:5, children: ['a', 'b', 'c']}
];


const arr2 = ['a', 'b'];

const matched = arr1.filter(({children: c}) => c.length === arr2.length && arr2.every(v => c.includes(v)))

console.log(matched)

【讨论】:

  • 考虑arr2 = abbchildren=abX
  • @georg Right...仅在 arr2 值唯一时有效。 OP不清楚这是否属实。如果使用Set 会是同样的问题
  • @charlietfl 对不起,我把这个例子简化得太多了。我添加了一个编辑部分。你能给我一个更新的解决方案吗?
【解决方案2】:

array1 = [
         {id:1, children: ['a', 'b']},
         {id:2, children: ['b', 'a']},
         {id:3, children: ['b', 'c']},
         {id:4, children: ['c', 'a']},
         {id:5, children: ['a', 'b', 'c']}];

array2 = ['a', 'b'];

const x = array1
  .map(a => a.children.sort())
  .filter(a => a.length === array2.length)
  .map(a => a.sort())
  .filter(a => JSON.stringify(a)==JSON.stringify(array2))

console.log(x)

【讨论】:

  • 仅在订单匹配但OP声明订单不重要时有效
【解决方案3】:

您可以使用Set 并根据此结构检查子级。

var array1 = [{ id: 1, children: ['a', 'b'] }, { id: 2, children: ['a', 'b'] }, { id: 3, children: ['b', 'c'] }, { id: 4, children: ['c', 'a'] },  { id: 5, children: ['a', 'b', 'c'] }],
    array2 = ['a', 'b'],
    set2 = new Set(array2),
    result = array1.filter(({ children }) =>
        children.length === set2.size && children.every(Set.prototype.has, set2));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

对于更复杂的数据结构,您可以解构所需的部分并检查一组subProductId

const
    getId = ({ subProduct: { subProductId } }) => subProductId;

var productOrders = [{ productId: 1, subProductOrders: [{ subProduct: { subProductId: 1 } }, { subProduct: { subProductId: 2 } }] }, { productId: 1, subProductOrders: [{ subProduct: { subProductId: 2 } }, { subProduct: { subProductId: 1 } }] }, { productId: 1, subProductOrders: [{ subProduct: { subProductId: 2 } }, { subProduct: { subProductId: 3 } }] }, { productId: 1, subProductOrders: [{ subProduct: { subProductId: 1 } }, { subProduct: { subProductId: 2 } }, { subProduct: { subProductId: 3 } }] }],
    matchingCriteria = [{ subProduct: { subProductId: 1 } }, { subProduct: { subProductId: 2 } }],
    set2 = new Set(matchingCriteria.map(getId)),
    result = productOrders.filter(({ subProductOrders }) =>
        subProductOrders.length === set2.size &&
        subProductOrders.every(o => set2.has(getId(o)))
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

  • 对不起,我把这个例子简化得太多了。我添加了一个编辑部分。你能给我一个更新的解决方案吗?
  • matchingCriteria 的其他项目会怎样,如果没有嵌套数组,只有一个数组不是更好吗?
  • 太棒了。这就像魅力一样。要回答您之前的问题,我只需要一些特定的 subProductOrders(带有 subProductId)来将一些产品与匹配的 subProductOrders 合并。因此,我为此目的仅使用 subProductOrders 制作了匹配条件数组。
  • 此编码的目的是,在 POS 系统中,用户可以添加特定产品(例如卡布奇诺)的多个子产品(顶部/附加组件等)。用户可以为每个卡布奇诺杯单元添加一个/多个浇头/附加组件。所以这里的目的是合并具有相同附加组件的单元并计算数量和总价。差不多就是这样
【解决方案4】:

您正在根据 element.children 与 array2 的相等性过滤 array1 元素。 所以我鼓励你看看这些answers。因为它讨论了 javascript 中两个数组的相等性。

并根据您的需要修改以下代码,这只是可用的最简单的选项之一:

array1.filter((element,index) => {
      return JSON.stringify(element.children) === JSON.stringify(array2)
})

【讨论】:

  • 使用 JSON.stringify 仅在顺序相同时有效
  • 我修改了我的答案,指出这是可用于两个数组相等的众多选项之一。
  • OK...但是 OP 已经声明顺序并不重要,因此这种方法在这种情况下不相关
  • return JSON.stringify(element.children.sort()) === JSON.stringify(array2.sort()) 在这种情况下也会失败吗?
  • 效率不是很高,如果需要维护订单,排序可能会引入其他问题。请注意,如果您确实使用了这种方法,则不需要每次迭代都执行 JSON.stringify(array2.sort())。执行一次并存储结果
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多