javascript - 当找到两个对象时,forEach 内部的过滤器无法正常工作

标签 javascript arrays object filter ecmascript-6

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

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

我想将新数据现有进行比较。如果 newdata 的对象具有相同的 id 和 cat,则它将不会出现在 new 数组中。

现有

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 不应该在那里,它已经在现有 中。

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

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 (内部)的方法,而不是 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; }

编辑

跟进,引用我的这条评论...

your comparison condition just does not fit what you are really searching/looking for.

如果仍然假设 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; }

关于javascript - 当找到两个对象时,forEach 内部的过滤器无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53632644/

相关文章:

php - 如何在php中获取动态生成的输入字段的值?

c++ - 从数组列表中用户搜索一个数字,如果没有找到,则只显示一个未找到的消息,而不是多次

c++ - 静态成员可以单独继承吗?

javascript - 使用 Moment.js 获取当前时间前 24 小时/1 天的时间

javascript - 检测和更改 mp3 链接 javaScript

c - 具有未知大小的结构数组的结构

c++ - 使用许多对象重载加法运算符 C++

Java 原始类型(例如 List 与 List<Object> )

javascript - 如果 Ajax 请求没有完成,html 链接无法点击

javascript - Jquery HTML 表本身