找到两个对象时,forEach中的过滤器无法正常工作

时间:2018-12-05 12:43:32

标签: javascript arrays object filter ecmascript-6

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

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

我想比较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。问题是我可以看到两次JakeJake不应该存在,它已经在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
    }
  }
];

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

请帮助我解决此问题。是我的过滤器还是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);

2 个答案:

答案 0 :(得分: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; }

EDIT

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

  

您的比较条件与您真正要查找/寻找的条件不符。

如果仍然认为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; }

答案 1 :(得分: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; }