【问题标题】:filter inside forEach does no work properly when finds double objects找到双重对象时,forEach 中的过滤器无法正常工作
【发布时间】:2019-05-07 01:01:32
【问题描述】:

我尝试获取数组的每个对象并将其与另一个数组的对象进行比较。如果它们匹配,则从第二个数组中删除该对象。

奇怪的是,如果在一个数组中两次找到一个对象,则该对象不会被过滤。

我想比较 newdataexisting。如果newdata 的对象具有相同的 id 和 cat,则它不会在新数组中。

existing

var existing = [{
    name: "John",
    values_: {
      id: 5,
      cat: true
    }
  },
  {name: "Jake",
    values_: {
      id: 3,
      cat: true
    }
  },
  {
    name: "Alice",
    values_: {
      id: 2,
      cat: false
    }
  }
];

newdata

var newdata = [{
    name: "Mike",
    properties: {
      id: 1,
      cat: true
    }
  },
  {name: "Jake",
    properties: {
      id: 3,
      cat: true
    }
  },
  {name: "Jake",
    properties: {
      id: 3,
      cat: true
    }
  },
  {
    name: "Alice",
    properties: {
      id: 2,
      cat: false
    }
  }
];

我的过滤器是

existing.forEach((existingitem, existingindex, existingfeatures) => {
  newdata2 = newdata.filter(item => (
    existingitem.values_.id != item.properties.id && 
    existingitem.values_.cat != item.properties.cat 

  ));
});

console.log('newdata2  - ',newdata2);

newdata2 的逻辑是只有 Mike 。问题是我可以看到Jake 两次。 Jake 不应该在那里,它已经在 existing 中。

如果我像这样编辑newdata(没有双打)

var newdata = [{
    name: "Mike",
    properties: {
      id: 1,
      cat: true
    }
  },
  {name: "Jake",
    properties: {
      id: 3,
      cat: true
    }
  } ,
  {
    name: "Alice",
    properties: {
      id: 2,
      cat: false
    }
  }
];

我仍然可以在newdata2 中看到Jake。但为什么?

请帮我解决这个问题。是我的过滤器还是filter 的工作方式?根据标准,最后我应该只得到Mike。请指教。

谢谢

    var existing = [{
        name: "John",
        values_: {
          id: 5,
          cat: true
        }
      },
      {name: "Jake",
        values_: {
          id: 3,
          cat: true
        }
      },
      {
        name: "Alice",
        values_: {
          id: 2,
          cat: false
        }
      }
    ]; 

    var newdata = [{
        name: "Mike",
        properties: {
          id: 1,
          cat: true
        }
      },
      {name: "Jake",
        properties: {
          id: 3,
          cat: true
        }
      },
      {name: "Jake",
        properties: {
          id: 3,
          cat: true
        }
      },
      {
        name: "Alice",
        properties: {
          id: 2,
          cat: false
        }
      }
    ];
 

    existing.forEach((existingitem, existingindex, existingfeatures) => {
      newdata2 = newdata.filter(item => (
        existingitem.values_.id != item.properties.id && 
        existingitem.values_.cat != item.properties.cat 
    
      ));
    });
    
    console.log('newdata2  - ',newdata2);

【问题讨论】:

  • ...考虑基于filter(外部)和every/some(内部)的方法,而不是forEachfilter - 也许这样更容易思考关于正确的实现。
  • 问题是你总是过滤原始的newdata数组并在每次迭代中覆盖之前的结果。因此,结果与您仅使用 existing 中的最后一项过滤时的结果相同。

标签: javascript arrays object filter ecmascript-6


【解决方案1】:

您可以使用Set 并过滤已知项目。

var existing = [{ name: "John", values_: { id: 5, cat: true } }, { name: "Jake", values_: { id: 3, cat: true } }, { name: "Alice", values_: { id: 2, cat: false } }],
    newdata = [{ name: "Mike", properties: { id: 1, cat: true } }, { name: "Jake", properties: { id: 3, cat: true } }, { name: "Jake", properties: { id: 3, cat: true } }, { name: "Alice", properties: { id: 2, cat: false } }],
    eSet = new Set(existing.map(({ values_: { id, cat } }) => [id, cat].join('|'))),
    result = newdata.filter(({ properties: { id, cat } }) => !eSet.has([id, cat].join('|')));

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

【讨论】:

  • 谢谢。我会尽快检查并通知您
  • 如果我理解正确,您可以使用map 将id 和cat 转换为字符串"id|cat"。然后将所有这些对放入一组。然后你filter newdata 通过再次转换 id, cat 到 "id|cat" 并使用 Set 的 has 与 Set 进行比较。不错的想法。但是:为什么要使用 |特点?如果明天所有的名字都有 | 怎么办?还有为什么要使用字符串?也许 Set 和 map 的另一种组合可以更好地证明未来?我可以帮助你想出一些更强大和更普遍的东西吗?无论如何,我会测试解决方案。谢谢
  • @codebot,如果你不喜欢使用 |作为分隔符,您可以使用值对数组进行序列化,例如 JSON([id, cat])。如果直接采用数组,它只能通过采用相同的对象引用来工作,这就是采用原语的原因。
【解决方案2】:

...考虑基于filter(外部)和every(内部)的方法,而不是forEachfilter - 也许这样更容易考虑正确的实现。

var existingItemList = [{ name: "John", values_: { id: 5, cat: true }}, { name: "Jake", values_: { id: 3, cat: true }}, { name: "Alice", values_: { id: 2, cat: false }}];
var newItemList = [{ name: "Mike", properties: { id: 1, cat: true }}, { name: "Jake", properties: { id: 3, cat: true }}, { name: "Jake", properties: { id: 3, cat: true }}, { name: "Alice", properties: { id: 2, cat: false }}];

var itemList = newItemList.filter(function (newItem) {    // filter `newItem` only
  return existingItemList.every(function (existingItem) { // if it does not exist
    return (                                              // in `existingItemList`.
    //(newItem.name !== existingItem.name) &&
      (newItem.properties.id !== existingItem.values_.id)
    );
  });
});

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

编辑

跟进,参考我的这个评论...

您的比较条件不适合您真正搜索/寻找的内容。

如果仍然假设 OP 想要过滤一个新项目,只有当它不存在于另一个将要与之进行比较的列表中时...

...必须编写一个匹配器函数,在同一时间映射和比较项目字段。

然后,这个比较器/匹配器必须以一种方式使用,它只过滤不等于任何其他现有项目的非常新的项目。

这可以通过对上面的前一种方法稍作改变来实现...

function doesExistingItemMatchBoundNewItem(existingItem) {
  var newItem = this;
  return (
       (newItem.properties.id === existingItem.values_.id)
    && (newItem.properties.cat === existingItem.values_.cat)
  );
}

var existingItemList = [{ name: "John", values_: { id: 5, cat: true }}, { name: "Jake", values_: { id: 3, cat: true }}, { name: "Alice", values_: { id: 2, cat: false }}];
var newItemList = [{ name: "Mike", properties: { id: 1, cat: true }}, { name: "Jake", properties: { id: 3, cat: true }}, { name: "Jake", properties: { id: 3, cat: true }}, { name: "Alice", properties: { id: 2, cat: false }}];

var itemList = newItemList.filter(function (newItem) {
  return !existingItemList.some(doesExistingItemMatchBoundNewItem.bind(newItem));
});

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

【讨论】:

  • 不错的想法,但如果我这样做(newItem.properties.id !== existingItem.values_.id) && (newItem.properties.cep !== existingItem.values_.cep),这将停止工作。
  • 新属性cep 应该是什么?
  • 哇哦!我提到了cat,而不是cep,但问题仍然存在
  • 您的比较条件不适合您真正搜索/寻找的内容。
  • @codebot ...我的原始答案中有一个“跟进”,现在也解决了这个问题。
猜你喜欢
  • 2020-11-17
  • 2013-09-15
  • 2019-11-12
  • 2015-02-02
  • 2015-02-14
  • 2013-08-16
  • 2012-11-16
相关资源
最近更新 更多