You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用单个reduce()优化代码,基于日志属性筛选正确开关门人员?

优化开关门日志代码:用单个reduce找出未关门的人

我家有三个人:['John', 'Jane', 'Jack'],我们记录了人员开关门的日志数据:

const logs = [
  { name: "John", status: "opened" },
  { name: "Jane", status: "opened" },
  { name: "Jack", status: "opened" },
  { name: "Jane", status: "closed" },
  { name: "Jack", status: "closed" },
];

从日志能看出,只有['Jane', 'Jack']完成了完整的开门+关门操作,John只开了门没关门。我现在用三步代码能识别出John:

let openers = logs.reduce((acc, log) => {
  if (log.status === "opened") {
    acc.push(log.name);
  }
  return acc;
}, []);

console.log(openers);

let closers = logs.reduce((acc, log) => {
  if (log.status === "closed") {
    acc.push(log.name);
  }
  return acc;
}, []);

console.log(closers);

let result = [];
closers.forEach((closer) => {
  if (openers.includes(closer)) {
    result.push(closer);
  }
});

console.log(result);

现在想把这三步逻辑用单个reduce()一次性完成,求代码优化方案。


优化方案1:状态标记统计法

通过reduce维护一个记录每个人操作状态的对象,最后筛选出只开门没关门的人:

const logs = [
  { name: "John", status: "opened" },
  { name: "Jane", status: "opened" },
  { name: "Jack", status: "opened" },
  { name: "Jane", status: "closed" },
  { name: "Jack", status: "closed" },
];

const unclosedPersons = Object.entries(
  logs.reduce((acc, { name, status }) => {
    // 初始化未记录人员的操作状态
    if (!acc[name]) {
      acc[name] = { opened: false, closed: false };
    }
    // 更新对应操作的状态标记
    acc[name][status] = true;
    return acc;
  }, {})
)
// 筛选出仅完成开门、未完成关门的人
.filter(([_, { opened, closed }]) => opened && !closed)
.map(([name]) => name);

console.log(unclosedPersons); // 输出: ["John"]

优化方案2:计数简化法

通过计数记录操作次数:开门加1、关门减1,最终计数为1的就是只开门没关门的人:

const logs = [
  { name: "John", status: "opened" },
  { name: "Jane", status: "opened" },
  { name: "Jack", status: "opened" },
  { name: "Jane", status: "closed" },
  { name: "Jack", status: "closed" },
];

const unclosedPersons = Object.entries(
  logs.reduce((acc, { name, status }) => {
    // 开门操作+1,关门操作-1,初始值默认为0
    acc[name] = (acc[name] || 0) + (status === "opened" ? 1 : -1);
    return acc;
  }, {})
)
// 计数为1说明仅存在开门操作,无对应关门操作
.filter(([_, count]) => count === 1)
.map(([name]) => name);

console.log(unclosedPersons); // 输出: ["John"]

这两种方案都只遍历日志一次,比原代码的三次遍历(两次reduce+一次forEach)效率更高,逻辑也更紧凑。

内容的提问来源于stack exchange,提问作者code-8

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 10:51:09