如何使用另一个对象数组来过滤一个对象数组?

3
我想使用另一个对象数组来过滤一个对象数组,就像下面的代码片段中所示:

const entries = [
  {
    id: 1,
    name: "Entry 1",
    topics: [
      {
        id: 101,
        name: "topic 1.1",
      },
      {
        id: 102,
        name: "topic 1.2",
      },
      {
        id: 103,
        name: "topic 1.3",
      },
    ],
  },
  {
    id: 2,
    name: "Entry 2",
    topics: [
      {
        id: 201,
        name: "topic 2.1",
      },
      {
        id: 202,
        name: "topic 2.2",
      },
      {
        id: 203,
        name: "topic 2.3",
      },
    ],
  },
  {
    id: 3,
    name: "Entry 3",
    topics: [
      {
        id: 25,
        name: "topic 3.1",
      },
      {
        id: 26,
        name: "topic 3.2",
      },
    ],
  },
];

const filters = [
  {
    id: 1,
    topics: [
      {
        id: 101,
      },
      {
        id: 102,
      },
    ],
  },
  {
    id: 2,
    topics: [],
  },
];

const result = entries
  .filter(({ id, topics }) =>
    filters.some(
      ({ id: idFromFilteres, topics: topicsFromFilters }) =>
        idFromFilteres === id && topicsFromFilters.length > 0,
    ),
  )
  .map(({ id, topics, ...rest }) => ({
    id,
    topics: topics?.filter(({ id: topicId }) =>
      filters.some(({ topics: topicsFromFilter }) =>
        topicsFromFilter.some(
          ({ id: topicIdFromFilter }) => topicIdFromFilter === topicId,
        ),
      ),
    ),
    ...rest,
  }));

console.log(result);

代码运行正常,但我不喜欢我再次迭代entries数组来过滤topics;还要注意,空topics的条目也会被过滤掉。
有没有办法在一次迭代中过滤这个数组?

听起来好像可以用reduce来做到这一点。 - undefined
为什么输出不包含id 2? - undefined
3个回答

1
关于filtermap函数,你怎么看?
// to map filter topics to entry IDs.
const map = new Map(filters.map((filter) => [filter.id, filter.topics.map((topic) => topic.id)]));

const result = entries.filter((entry) => {
  const topics = map.get(entry.id);
  return topics && topics.length > 0;
}).map((entry) => {
  const topics = map.get(entry.id);
  entry.topics = entry.topics.filter((topic) => topics.includes(topic.id));
  return entry;
});
  • filter: 删除没有匹配过滤器主题的条目
  • map: 为剩余的条目筛选主题

1
使用Array::reduce()同时进行过滤和映射:

const result = entries.reduce((r, entry) => {
  const found = filters.find(({ id }) => entry.id === id);
  if (found) {
    const topics = entry.topics.filter(({ id }) => found.topics.some((topic) => topic.id === id));
    topics.length && r.push({...entry, topics});
  }
  return r;
}, []);

console.log(result);
<script>
const entries = [
  {
    id: 1,
    name: "Entry 1",
    topics: [
      {
        id: 101,
        name: "topic 1.1",
      },
      {
        id: 102,
        name: "topic 1.2",
      },
      {
        id: 103,
        name: "topic 1.3",
      },
    ],
  },
  {
    id: 2,
    name: "Entry 2",
    topics: [
      {
        id: 201,
        name: "topic 2.1",
      },
      {
        id: 202,
        name: "topic 2.2",
      },
      {
        id: 203,
        name: "topic 2.3",
      },
    ],
  },
  {
    id: 3,
    name: "Entry 3",
    topics: [
      {
        id: 25,
        name: "topic 3.1",
      },
      {
        id: 26,
        name: "topic 3.2",
      },
    ],
  },
];

const filters = [
  {
    id: 1,
    topics: [
      {
        id: 101,
      },
      {
        id: 102,
      },
    ],
  },
  {
    id: 2,
    topics: [],
  },
];
</script>


1
你可以使用reduce()来遍历entries数组,并根据filters数组进行过滤。
示例:
const result = entries.reduce((filteredEntries, entry) => {
  const matchingFilter = filters.find((filter) => filter.id === entry.id);

  if (matchingFilter) {
    const filteredTopics = entry.topics.filter((topic) =>
      matchingFilter.topics.some((filterTopic) => filterTopic.id === topic.id),
    );

    if (filteredTopics.length > 0) {
      filteredEntries.push({ ...entry, topics: filteredTopics });
    }
  }

  return filteredEntries;
}, []);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接