用另一个对象数组过滤对象数组

时间:2018-12-03 22:39:50

标签: javascript arrays filter

我想用另一个对象数组过滤对象数组。

我有2个这样的对象数组:

<div id="list">

</div>

,我想用const array = [ { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } }, { id: 2, name: 'a2', sub: null }, { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } }, { id: 4, name: 'a4', sub: null }, { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } }, ]; const anotherArray = [ { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } }, { id: 2, name: 'a2', sub: null }, { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } }, ]; 过滤array并返回在anotherArray中不存在且具有sub的项。

所以我想要的输出是:

anotherArray

注意:我已经使用for循环完成了此操作,但是它工作太慢。我想通过使用数组过滤器方法来做到这一点

我使用for循环的代码:

[ { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } ]

5 个答案:

答案 0 :(得分:2)

您可以先使用Array.filter,然后再使用Array.some,因为后者将返回布尔值,而不是像Array.find这样的元素:

const a1 = [ { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } }, { id: 2, name: 'a2', sub: null }, { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } }, { id: 4, name: 'a4', sub: null }, { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } }, ]; 
const a2 = [ { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } }, { id: 2, name: 'a2', sub: null }, { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } }, ];

const result = a1.filter(({id, sub}) => !a2.some(x => x.id == id) && sub)

console.log(result)

答案 1 :(得分:1)

好的,让我们逐步解决这个问题。

为简化该过程,我们假设两个元素如果具有相同的id,则可以认为是相等的。

我将使用的第一种方法是迭代第一个数组,并针对每个元素迭代第二个数组以检查您在上面定义的条件。

const A = [ /* ... */]
const B = [ /* ... */]

A.filter(el => {
  let existsInB = !!B.find(e => {
    return e.id === el.id
  }

  return existsInB && !!B.sub
})

如果我们确定A和B中的元素具有相同的ID时,它们确实是相同的,那么我们可以跳过没有sub属性的所有A元素来对其执行一点操作

A.filter(el => {
  if (!el.sub) return false

  let existsInB = !!B.find(e => {
    return e.id === el.id
  }

  return existsInB
})

现在,如果我们的数组大于该数组,则意味着我们正在浪费大量时间在B中寻找元素。 通常,在这种情况下,我将要查找的数组转换为地图,就像这样

var BMap = {}
B.forEach(el => {
  BMap[el.id] = el
})

A.filter(el => {
  if (!el.sub) return false

  return !!BMap[el.id]
})

通过这种方式,您一开始就“浪费”了一点时间来创建地图,但是随后您可以更快地找到元素。

从这里可能会有更多的优化,但是我认为这足以解决这个问题

答案 2 :(得分:0)

就像Felix提到的那样,Array#filter的运行速度不会比原生for循环快,但是,如果您真的希望将其作为功能性方式,则可以采用以下一种解决方案:

const array = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } },
    { id: 4, name: 'a4', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];

const anotherArray = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];

const r = array.filter((elem) => !anotherArray.find(({ id }) => elem.id === id) && elem.sub);

console.log(r);

答案 3 :(得分:0)

您可以使用JSON.stringify比较两个对象。最好编写一个函数来递归比较对象上的所有属性。

const array = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } },
    { id: 4, name: 'a4', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];
const anotherArray = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];

const notIn = (array1, array2) => array1.filter(item1 => {
    const item1Str = JSON.stringify(item1);
    return !array2.find(item2 => item1Str === JSON.stringify(item2))
  }
);

console.log(notIn(array, anotherArray));

答案 4 :(得分:0)

优化版本:不需要每次都搜索元素(用find),创建一个字典并在O(1)##中搜索

const array = [{
    id: 1,
    name: "a1",
    sub: {
      id: 6,
      name: "a1 sub"
    }
  },
  {
    id: 2,
    name: "a2",
    sub: null
  },
  {
    id: 3,
    name: "a3",
    sub: {
      id: 8,
      name: "a3 sub"
    }
  },
  {
    id: 4,
    name: "a4",
    sub: null
  },
  {
    id: 5,
    name: "a5",
    sub: {
      id: 10,
      name: "a5 sub"
    }
  },
];
const anotherArray = [{
    id: 1,
    name: "a1",
    sub: {
      id: 6,
      name: "a1 sub"
    }
  },
  {
    id: 2,
    name: "a2",
    sub: null
  },
  {
    id: 5,
    name: "a5",
    sub: {
      id: 10,
      name: "a5 sub"
    }
  },
];

const dict = anotherArray.reduce((acc, curr) => {
  const { id } = curr;
  acc[id] = curr;
  return acc;
}, {});

const result = array.filter((obj) => {
  const search = dict[obj.id];
  if (!search && obj.sub) return true;
  return false;
});

console.log(result);