0

0

如何在 JavaScript 中根据键值比较两个对象并计算总和

心靈之曲

心靈之曲

发布时间:2025-12-05 15:30:27

|

448人浏览过

|

来源于php中文网

原创

如何在 JavaScript 中根据键值比较两个对象并计算总和

本文旨在指导读者如何在 javascript 中有效地根据两个对象的键值进行比较并计算特定属性的总和。我们将探讨多种实现策略,包括利用 `reduce` 方法进行链式操作,以及通过构建查找表或键集合来简化逻辑,最终实现对匹配项分数的累加。

在 JavaScript 开发中,我们经常需要处理结构化数据,并根据特定条件对数据进行聚合。一个常见的场景是,我们有两个对象:一个包含用户的选择或答案,另一个则存储了所有可能选项对应的分数。我们的目标是根据用户的选择,从分数对象中找出对应的分数并计算总和。

场景描述与数据结构

假设我们有以下两个 JavaScript 对象:

  1. values 对象:代表用户的选择或答案。它是一个嵌套对象,外层键通常代表问题 ID(如 Q1),内层对象包含用户选择的答案 ID(如 Q1A1)及其对应的状态(如 "Yes" 或 "No")。
  2. points 对象:存储了所有可能的答案 ID 及其对应的分数。它是一个扁平对象,键是答案 ID,值是分数。

示例数据:

const values = {
    Q1: {
        Q1A1: "Yes",
    },
    Q2: {
        Q2A1: "Yes",
    },
    Q3: {
        Q3A2: "No",
    },
};

const points = {
    Q1A1: 41,
    Q1A2: 0,
    Q2A1: 19,
    Q2A2: 0,
    Q3A1: 25,
    Q3A2: 0,
};

根据上述数据,如果用户选择了 Q1A1 ("Yes") 和 Q2A1 ("Yes"),并且 Q3A2 ("No") 不计入分数,那么期望的总和是 points.Q1A1 (41) + points.Q2A1 (19) = 60。

立即学习Java免费学习笔记(深入)”;

接下来,我们将介绍几种实现此计算的方法。

方法一:使用嵌套的 reduce 方法

这种方法利用 Array.prototype.reduce() 的强大功能,通过两次迭代来聚合数据。外层 reduce 遍历 values 对象的问题,内层 reduce 遍历每个问题下的答案。

const values = {
    Q1: { Q1A1: "Yes" },
    Q2: { Q2A1: "Yes" },
    Q3: { Q3A2: "No" },
};

const points = {
    Q1A1: 41,
    Q1A2: 0,
    Q2A1: 19,
    Q2A2: 0,
    Q3A1: 25,
    Q3A2: 5, // 即使有分,如果 'No' 也不计
};

const total = Object.values(values) // 获取 values 对象的所有值 (即 Q1, Q2, Q3 对应的子对象)
  .reduce((acc, cur) => { // 外层 reduce 累加每个问题下的分数
    return acc + Object.entries(cur) // 获取当前问题子对象的所有键值对 (如 ['Q1A1', 'Yes'])
      .reduce((accInner, [key, val]) => { // 内层 reduce 处理单个答案
        // 检查答案值是否不为 'No' 且 points 对象中存在对应的键
        if (val !== 'No' && points[key]) {
          return accInner + points[key]; // 如果满足条件,累加对应的分数
        }
        return accInner; // 否则不累加
      }, 0); // 内层 reduce 的初始累加值为 0
  }, 0); // 外层 reduce 的初始累加值为 0

console.log(total); // 输出: 60

解释:

炉米Lumi
炉米Lumi

字节跳动推出的AI模型分享社区和模型训练平台

下载
  1. Object.values(values):将 values 对象转换为一个数组,其中包含 Q1, Q2, Q3 对应的子对象。
  2. 外层 reduce:遍历这些子对象,acc 是总分数累加器,cur 是当前的问题子对象(例如 { Q1A1: "Yes" })。
  3. Object.entries(cur):将当前问题子对象转换为一个键值对数组(例如 [['Q1A1', 'Yes']])。
  4. 内层 reduce:遍历这些键值对。accInner 是当前问题下的分数累加器,[key, val] 是当前的答案 ID 和其值。
  5. 条件判断 val !== 'No' && points[key]:
    • val !== 'No' 确保只有非 "No" 的答案才会被考虑。
    • points[key] 检查 points 对象中是否存在对应的答案 ID,并且它的值非零或非 undefined(尽管 points[key] 为 0 时 accInner + 0 不影响结果,但此检查通常用于确保键存在)。
  6. 如果条件为真,将 points[key] 的值加到 accInner。
  7. 最终,外层 reduce 返回所有问题分数的总和。

方法二:构建查找表并结合 filter 和 reduce

这种方法首先从 values 对象中创建一个简化的查找表,只包含需要计分的答案 ID。然后,利用这个查找表对 points 对象进行过滤和求和。这种方法通常更易于阅读和理解。

const values = {
    Q1: { Q1A1: "Yes" },
    Q2: { Q2A1: "Yes" },
    Q3: { Q3A2: "No" },
};

const points = {
    Q1A1: 41,
    Q1A2: 0,
    Q2A1: 19,
    Q2A2: 0,
    Q3A1: 25,
    Q3A2: 5,
};

// 1. 构建一个查找表,只包含需要计分的答案ID
const lookup = Object.values(values).reduce((acc, cur) => {
  const [key, val] = Object.entries(cur)[0]; // 每个子对象只有一个键值对
  if (val === "Yes") { // 只将值为 "Yes" 的答案加入查找表
    acc[key] = true; // 可以是任何真值,这里用 true 表示存在
  }
  return acc;
}, {});

console.log("Lookup table:", lookup); // 输出: { Q1A1: true, Q2A1: true }

// 2. 遍历 points 对象,根据查找表过滤并求和
const totalPoints = Object.entries(points) // 获取 points 对象的所有键值对
  .filter(([key, score]) => lookup[key]) // 过滤:只保留在 lookup 表中存在的键
  .reduce((sum, [key, score]) => sum + score, 0); // 求和:累加过滤后的分数

console.log(totalPoints); // 输出: 60

解释:

  1. 构建 lookup 表:
    • Object.values(values).reduce(...) 遍历 values 对象。
    • 对于每个问题子对象,提取其唯一的键值对 [key, val]。
    • 如果 val 为 "Yes",则将 key 作为属性添加到 lookup 对象中,值为 true(或任何真值),表示该答案需要计分。
  2. 过滤并求和:
    • Object.entries(points) 将 points 对象转换为键值对数组。
    • filter(([key, score]) => lookup[key]):过滤掉那些键不在 lookup 表中的条目。只有 Q1A1 和 Q2A1 会通过过滤。
    • reduce((sum, [key, score]) => sum + score, 0):对过滤后的键值对进行求和,累加 score。

方法三:提取关键答案 ID 集合并使用 filter 和 reduce

如果 values 对象中答案的值(如 "Yes" / "No")不影响是否计分,而仅仅是键的存在决定是否计分,或者我们只需要收集所有选定的答案 ID,可以使用 Set 来存储这些键,从而提高查找效率。

const values = {
    Q1: { Q1A1: "Yes" },
    Q2: { Q2A1: "Yes" },
    Q3: { Q3A2: "No" }, // 这里的 "No" 依然会被提取键,如果逻辑需要
};

const points = {
    Q1A1: 41,
    Q1A2: 0,
    Q2A1: 19,
    Q2A2: 0,
    Q3A1: 25,
    Q3A2: 5,
};

// 1. 提取所有需要计分的答案ID到一个 Set 中
const selectedAnswerKeys = new Set(
  Object.values(values).map(question => Object.keys(question)[0])
);

console.log("Selected Answer Keys:", selectedAnswerKeys); // 输出: Set(3) { 'Q1A1', 'Q2A1', 'Q3A2' }

// 2. 遍历 points 对象,根据 Set 过滤并求和
const totalSum = Object.entries(points)
  .filter(([key, score]) => selectedAnswerKeys.has(key)) // 过滤:只保留在 Set 中存在的键
  .reduce((acc, [key, score]) => acc + score, 0); // 求和

console.log(totalSum); // 输出: 65 (因为 Q3A2 即使是 "No",其键也被提取并计分了 5)

注意: 此方法默认只要 values 对象中存在某个答案 ID,就将其计入总和,而不考虑其关联的 "Yes" / "No" 状态。如果需要考虑状态,应结合方法二的逻辑。

总结与注意事项

本文介绍了三种在 JavaScript 中根据键值比较两个对象并计算总和的方法:

  1. 嵌套 reduce: 适用于复杂的多层条件判断,但代码可能略显紧凑,可读性稍差。
  2. 构建查找表 + filter + reduce: 这种方法将逻辑分解为两个清晰的步骤(构建查找表和基于查找表过滤求和),通常更易于理解和维护,尤其当过滤条件涉及 values 对象中的具体值时(如 "Yes")。
  3. 提取键集合 + filter + reduce: 当仅关注键的存在性而忽略其关联值时,此方法简洁高效,利用 Set 进行快速查找。

选择建议:

  • 如果需要根据 values 对象中答案的具体值(如 "Yes" / "No")来决定是否计分,方法二(构建查找表)是最佳选择,它清晰地分离了条件判断和求和逻辑。
  • 如果 values 对象中的答案只要存在就计分(忽略其值),方法三(提取键集合)效率较高。
  • 方法一(嵌套 reduce)虽然功能强大,但在处理这种特定场景时,可能会牺牲一些可读性,但对于一次性完成所有操作的场景也很适用。

在实际开发中,请根据您的具体业务逻辑和团队的代码风格偏好来选择最合适的方法。同时,始终考虑代码的可读性、可维护性以及在处理大量数据时的性能表现。

相关专题

更多
js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

556

2023.06.20

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

374

2023.07.04

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

732

2023.07.04

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

477

2023.09.01

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

414

2023.09.04

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

991

2023.09.04

如何启用JavaScript
如何启用JavaScript

JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

658

2023.09.12

Js中Symbol类详解
Js中Symbol类详解

javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

553

2023.09.20

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

72

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 3.8万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.3万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 2.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号