Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
JavaScript:从对象数组中提取并保留唯一键值对_创想鸟

JavaScript:从对象数组中提取并保留唯一键值对

javascript:从对象数组中提取并保留唯一键值对

本教程旨在详细阐述如何在JavaScript中高效处理包含重复键值对的对象数组。通过采用`reduce`方法结合一个`seen`映射表来追踪已处理的键值对,我们可以有效地过滤掉后续对象中出现的重复项。文章将提供清晰的算法思路、具体的代码实现及使用示例,帮助开发者构建一个新数组,其中每个对象仅包含首次出现的独特键值对,从而实现数据的去重和结构优化。

引言:理解问题与目标

在JavaScript开发中,我们经常会遇到需要处理包含复杂数据的数组,其中每个元素都是一个对象。有时,这些对象之间可能存在键值对的重复。例如,在一个对象数组中,如果第一个对象包含”Param1″: “20”,而后续某个对象也包含”Param1″: “20”,我们的目标是移除后续对象中的这个重复键值对,只保留第一次出现的。这要求我们遍历数组,并对每个对象的键值对进行去重判断,确保最终结果中的每个键值对都是全局唯一的(即在之前的对象中未出现过)。

考虑以下示例输入:

const arr1 = [  { "Param1": "20", "Param2": "8", "Param3": "11", "Param4": "4", "Param5": "18", "Param6": "20", "Param7": "8" },  { "Param6": "21", "Param7": "8", "Param8": "11", "Param9": "4", "Param10": "18" },  { "Param1": "20", "Param2": "8", "Param3": "10" }];

我们期望的输出是:

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

[  { "Param1": "20", "Param2": "8", "Param3": "11", "Param4": "4", "Param5": "18", "Param6": "20", "Param7": "8" },  { "Param6": "21", "Param8": "11", "Param9": "4", "Param10": "18" }, // "Param7": "8" 被移除,因为它在第一个对象中已出现  { "Param3": "10" } // "Param1": "20" 和 "Param2": "8" 被移除,因为它们在第一个对象中已出现];

注意,去重是基于key和value的组合,并且是顺序敏感的——即如果一个键值对在数组中较早的对象中出现过,它在后续对象中就会被移除。

核心算法思路

为了实现上述目标,我们需要一个机制来追踪所有已经遇到的键值对。我们可以使用一个嵌套的映射结构(或JavaScript对象)来充当这个“已见”集合。

具体算法步骤如下:

初始化追踪器: 创建一个名为 seen 的空对象(或 Map),其结构为 { [key: string]: { [value: string]: boolean } }。这个结构将用于记录某个 key 对应某个 value 是否已经出现过。初始化结果数组: 创建一个空的 result 数组,用于存放处理后的对象。遍历输入数组: 逐个处理输入数组中的每个对象。处理当前对象: 对于当前对象,遍历其所有的键值对。对于每个 [key, value] 对:首先,确保 seen 对象中存在 key 对应的内层对象。如果不存在,则初始化为 {}。检查 seen[key][value] 是否为 true。如果为 true,表示这个 key: value 对之前已经出现过,则忽略它(不将其添加到当前正在构建的新对象中)。如果为 false 或 undefined,表示这个 key: value 对是首次出现。将其添加到当前正在构建的新对象中,并在 seen[key][value] 中标记为 true。构建新对象并添加: 将所有通过筛选的键值对重新组合成一个新的对象,并将其添加到 result 数组中。返回结果: 遍历完成后,返回 result 数组。

示例代码实现

在JavaScript中,Array.prototype.reduce() 方法非常适合这种需要遍历数组并累积结果的场景。我们将使用 reduce 来维护 seen 追踪器和 result 数组。

/** * 从对象数组中移除重复的键值对。 * 如果一个键值对在数组中较早的对象中出现过,则在后续对象中将其移除。 * * @param arr 包含待处理对象的数组。每个对象都是一个键值对集合。 * @returns 包含唯一键值对的新对象数组。 */const removeDuplicates = (arr: Record[]) => {    // 使用 reduce 方法迭代数组并累积结果    return arr.reduce<{        seen: Record<string, Record>; // 追踪已见键值对的映射        result: Record[]; // 存储处理后对象的数组    }>(        (accumulator, currentItem) => {            // 为当前对象创建一个新的对象,只包含唯一的键值对            const uniqueItem = Object.fromEntries(                // 遍历当前对象的键值对,并进行过滤                Object.entries(currentItem).filter(([key, value]) => {                    // 确保 seen[key] 存在,如果不存在则初始化为空对象                    accumulator.seen[key] = accumulator.seen[key] ?? {};                    // 检查当前键值对是否已在 seen 映射中标记为 true                    if (accumulator.seen[key][value]) {                        // 如果已存在,则过滤掉此键值对 (返回 false)                        return false;                    }                    // 如果是首次出现,则标记为已见 (设置为 true)                    accumulator.seen[key][value] = true;                    // 保留此键值对 (返回 true)                    return true;                }),            );            // 将处理后的唯一对象添加到结果数组中            accumulator.result.push(uniqueItem);            return accumulator;        },        // reduce 的初始值:一个包含空 seen 映射和空 result 数组的对象        { seen: {}, result: [] },    ).result; // 最后返回累加器中的 result 数组};// 示例使用const arr1 = [  { "Param1": "20", "Param2": "8", "Param3": "11", "Param4": "4", "Param5": "18", "Param6": "20", "Param7": "8" },  { "Param6": "21", "Param7": "8", "Param8": "11", "Param9": "4", "Param10": "18" },  { "Param1": "20", "Param2": "8", "Param3": "10" }];const uniqueArr = removeDuplicates(arr1);console.log(uniqueArr);/*预期的输出:[  { "Param1": "20", "Param2": "8", "Param3": "11", "Param4": "4", "Param5": "18", "Param6": "20", "Param7": "8" },  { "Param6": "21", "Param8": "11", "Param9": "4", "Param10": "18" },  { "Param3": "10" }]*/

代码解析:

removeDuplicates 函数: 接收一个对象数组作为参数。arr.reduce(…): 这是核心的迭代和累积过程。accumulator (累加器): 初始值为 { seen: {}, result: [] }。seen 对象用于存储已见的键值对,result 数组用于存储最终处理后的对象。currentItem: 当前正在处理的数组中的对象。Object.entries(currentItem): 将当前对象转换为 [key, value] 对的数组。.filter(([key, value]) => { … }): 对 [key, value] 对进行过滤。accumulator.seen[key] = accumulator.seen[key] ?? {};:这是ES2020的空值合并运算符。它确保 accumulator.seen[key] 存在。如果 accumulator.seen[key] 是 null 或 undefined,则将其初始化为一个空对象 {}。if (accumulator.seen[key][value]) return false;:检查当前 key: value 对是否已经在 seen 映射中被标记为 true。如果是,则表示它已出现过,filter 返回 false 将其移除。accumulator.seen[key][value] = true;:如果当前 key: value 对是首次出现,则在 seen 映射中将其标记为 true,表示已见过。return true;:首次出现的键值对通过 filter 筛选。Object.fromEntries(…): 将过滤后的 [key, value] 对数组重新组合成一个新的对象 uniqueItem。accumulator.result.push(uniqueItem);: 将新生成的 uniqueItem 添加到结果数组中。return accumulator;: 返回更新后的累加器,供下一次迭代使用。.result: reduce 方法执行完毕后,我们从最终的累加器中提取 result 数组,即为我们所需的结果。

注意事项与扩展

顺序敏感性: 此方案严格遵循输入数组的顺序。如果输入数组的顺序改变,输出结果也可能不同,因为“首次出现”的定义是基于遍历顺序的。值类型: 示例中键值对的值是字符串。对于其他原始数据类型(如数字、布尔值),此方法同样适用,因为它们在JavaScript中可以直接作为对象键或属性值进行比较。但对于非原始值(如对象、数组),value 的比较将是引用比较,而不是深层内容比较。如果需要深层比较,则需要对 value 进行序列化(例如 JSON.stringify(value))或实现自定义的深层比较逻辑。性能考量:时间复杂度:对于一个包含 N 个对象的数组,每个对象平均有 M 个键值对。reduce 迭代 N 次,每次迭代中 Object.entries 和 filter 都会遍历 M 个键值对。在 filter 内部,对象属性访问(如 seen[key][value])通常是 O(1) 操作。因此,整体时间复杂度大致为 O(N * M)。空间复杂度:seen 对象可能存储所有唯一的键值对,最坏情况下,如果所有键值对都唯一,则空间复杂度为 O(N * M)。TypeScript 类型: 示例代码使用了 TypeScript 类型注解 (Record[]),这有助于提高代码的可读性和健壮性。在纯 JavaScript 环境中,可以直接移除类型注解。

总结

通过本教程,我们学习了一种在JavaScript中从对象数组中提取并保留唯一键值对的有效方法。利用 Array.prototype.reduce() 结合一个嵌套的 seen 对象作为追踪器,我们能够灵活且高效地处理复杂的数据去重需求。这种方法不仅清晰地解决了特定问题,也展示了 reduce 在数据转换和聚合方面的强大能力。在实际开发中,理解其顺序敏感性和对不同值类型的处理方式,将帮助我们更好地应用此模式。

以上就是JavaScript:从对象数组中提取并保留唯一键值对的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1540699.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
提升带取消选中功能的单选按钮可点击区域的完整指南
上一篇 2025年12月21日 12:40:56
JavaScript中typeof null的陷阱与安全条件判断
下一篇 2025年12月21日 12:41:12

相关推荐

  • 使用 Jackson 进行复杂类的自定义反序列化

    使用 Jackson 进行复杂类的自定义反序列化使用 Jackson 进行复杂类的自定义反序列化使用 Jackson 进行复杂类的自定义反序列化使用 Jackson 进行复杂类的自定义反序列化

    本文介绍了如何使用 Jackson 库对包含复杂嵌套类的 JSON 字符串进行自定义反序列化。通过 ObjectMapper 的 readValue 方法可以实现简单场景下的自动反序列化。针对需要定制化处理的场景,可以结合 ObjectMapper 和自定义反序列化器来实现更灵活的反序列化逻辑,并提…

    2026年9月25日 • 用户投稿
    900
  • 使用 JSON Schema 中的 oneOf 避免无效枚举值的错误提示

    使用 JSON Schema 中的 oneOf 避免无效枚举值的错误提示使用 JSON Schema 中的 oneOf 避免无效枚举值的错误提示使用 JSON Schema 中的 oneOf 避免无效枚举值的错误提示使用 JSON Schema 中的 oneOf 避免无效枚举值的错误提示

    本文旨在帮助开发者理解并解决在使用 JSON Schema 验证 JSON 数据时,由于 oneOf 约束可能导致的“无效枚举值”的错误提示问题。我们将通过示例代码,详细解释错误产生的原因,并提供相应的解决方案,以确保 JSON Schema 验证的准确性和可读性。 在使用 JSON Schema …

    2026年9月25日 • 用户投稿
    500
  • 动态缓存键配置:Spring Boot 缓存管理的灵活应用

    动态缓存键配置:Spring Boot 缓存管理的灵活应用动态缓存键配置:Spring Boot 缓存管理的灵活应用动态缓存键配置:Spring Boot 缓存管理的灵活应用动态缓存键配置:Spring Boot 缓存管理的灵活应用

    在 Spring Boot 应用中,使用 @Cacheable 注解可以方便地实现缓存功能。然而,在某些场景下,我们需要根据请求参数动态地生成缓存键,而不是简单地使用固定的键值。虽然 @Cacheable 注解允许通过 key 属性指定 SpEL 表达式来生成缓存键,但有时我们可能需要更灵活的控制,…

    2026年9月25日 • 用户投稿
    200
  • p5.js WebGL性能优化:首帧渲染耗时长的原因与对策

    p5.js WebGL性能优化:首帧渲染耗时长的原因与对策p5.js WebGL性能优化:首帧渲染耗时长的原因与对策p5.js WebGL性能优化:首帧渲染耗时长的原因与对策p5.js WebGL性能优化:首帧渲染耗时长的原因与对策

    在使用p5.js的WEBGL渲染模式时,首次调用image()函数渲染图片或p5.Graphics对象通常会比后续调用耗时显著增加。这主要是因为第一次渲染时,p5.js需要将图像数据从CPU内存上传到GPU的纹理内存中,涉及内存分配和数据复制,这是一个相对耗时的过程。后续调用由于纹理已被缓存,可以直…

    2026年9月25日 • 用户投稿
    700
  • 动态缓存键在Spring Boot中的实现教程

    动态缓存键在Spring Boot中的实现教程动态缓存键在Spring Boot中的实现教程动态缓存键在Spring Boot中的实现教程动态缓存键在Spring Boot中的实现教程

    本文介绍了如何在Spring Boot应用中实现基于请求参数的动态缓存键。通过直接操作CacheManager获取缓存对象,并使用cache.get(key, () -> …)方法,可以灵活地根据请求参数生成缓存键,从而实现更精细化的缓存控制。这种方法避免了直接修改缓存名称,而是专…

    2026年9月25日 • 用户投稿
    700
  • sublime怎么配置eslint进行js校验_sublime集成ESLint代码检查配置

    sublime怎么配置eslint进行js校验_sublime集成ESLint代码检查配置sublime怎么配置eslint进行js校验_sublime集成ESLint代码检查配置sublime怎么配置eslint进行js校验_sublime集成ESLint代码检查配置sublime怎么配置eslint进行js校验_sublime集成ESLint代码检查配置

    首先安装SublimeLinter和SublimeLinter-eslint插件,确保系统或项目中已安装ESLint;通过npx eslint –init生成配置文件;插件会自动调用项目内的eslint,若未识别可手动设置executable路径;保存JavaScript文件时即可实时显…

    2026年9月25日 • 用户投稿
    000
  • Java 8 使用 Stream API 扁平化嵌套 Map 并提取首个元素

    Java 8 使用 Stream API 扁平化嵌套 Map 并提取首个元素Java 8 使用 Stream API 扁平化嵌套 Map 并提取首个元素Java 8 使用 Stream API 扁平化嵌套 Map 并提取首个元素Java 8 使用 Stream API 扁平化嵌套 Map 并提取首个元素

    本文将详细介绍如何使用 Java 8 的 Stream API 将一个嵌套的 Map 结构进行扁平化处理,并从中提取所需的数据。 具体来说,我们将把 Map<Integer, Map<String, List>> 转换为 Map,其中新 Map 的键是原内部 Map 的键,值…

    2026年9月25日 • 用户投稿
    1200
  • 修改 Android KeyStore 中 KeyPair 的用途

    修改 Android KeyStore 中 KeyPair 的用途修改 Android KeyStore 中 KeyPair 的用途修改 Android KeyStore 中 KeyPair 的用途修改 Android KeyStore 中 KeyPair 的用途

    本文档介绍了如何在 Android KeyStore 中修改现有 KeyPair 的用途,使其支持密钥协商 (Key Agreement) 操作。通过示例代码展示了如何利用 KeyStore.setEntry 方法在 Android 13 (API 33) 及以上版本中导入 KeyPair 并设置所…

    2026年9月25日 • 用户投稿
    600
  • 并发处理共享列表并收集结果的方案

    并发处理共享列表并收集结果的方案并发处理共享列表并收集结果的方案并发处理共享列表并收集结果的方案并发处理共享列表并收集结果的方案

    本文旨在介绍如何利用 Java 并行流高效地处理大型列表,尤其是在每个元素的处理过程耗时较长的情况下。并行流能够将列表分割成多个子任务,并在多个线程上并发执行,从而显著提升处理速度。但同时,并发编程也带来了共享资源同步的问题,需要谨慎处理。 使用并行流并发处理列表 假设我们有一个 Foo 类,其 p…

    2026年9月25日 • 用户投稿
    000
  • 高效并发处理共享列表与结果收集的Java教程

    高效并发处理共享列表与结果收集的Java教程高效并发处理共享列表与结果收集的Java教程高效并发处理共享列表与结果收集的Java教程高效并发处理共享列表与结果收集的Java教程

    本文介绍了如何利用Java并发特性,特别是并行流(Parallel Streams),来高效处理共享列表,并将处理结果进行收集。针对耗时操作,通过将列表分割成子列表,并利用并行流并发执行,可以显著提高处理效率。同时,强调了在并发环境下对共享资源进行同步的重要性,并提供了收集处理结果的示例代码。 在处…

    2026年9月25日 • 用户投稿
    000
  • 使用并行流并发处理共享列表并收集结果

    使用并行流并发处理共享列表并收集结果使用并行流并发处理共享列表并收集结果使用并行流并发处理共享列表并收集结果使用并行流并发处理共享列表并收集结果

    本文将探讨如何高效地并发处理共享列表,并收集处理结果。在处理大量数据时,将任务分解为多个子任务并行执行可以显著提高效率。Java 8引入的并行流(Parallel Streams)为我们提供了一种简洁而强大的方式来实现这一目标。 并行流简介 并行流是Java 8 Stream API的一个特性,它允…

    2026年9月25日 • 用户投稿
    400
  • 如何在微服务之间共享静态数据

    如何在微服务之间共享静态数据如何在微服务之间共享静态数据如何在微服务之间共享静态数据如何在微服务之间共享静态数据

    微服务架构的本质决定了微服务之间无法直接共享静态变量。正如上面摘要所说,每个微服务都是一个独立的进程,拥有自己的内存空间,静态变量只在其所属的进程内有效。试图在一个微服务中访问另一个微服务的静态变量,就像试图在一个独立的Java程序中访问另一个程序的变量一样,是不可能的。 微服务架构的独立性 微服务…

    2026年9月25日 • 用户投稿
    100
  • FineReport与.NET集成要点

    FineReport与.NET集成要点FineReport与.NET集成要点FineReport与.NET集成要点FineReport与.NET集成要点

    1、FineReport(FR)与.NET项目的集成主要涵盖三个核心部分,如上图所示。 2、报表发布是集成过程中的关键步骤之一。 3、需要注意的是,FR报表工程本质上是基于Java的Servlet应用,无法由IIS直接解析处理,因此必须将其部署在支持Servlet规范的Web应用服务器(如Tomca…

    2026年9月25日 • 用户投稿
    200
  • 如何在微服务之间共享静态数据?

    如何在微服务之间共享静态数据?如何在微服务之间共享静态数据?如何在微服务之间共享静态数据?如何在微服务之间共享静态数据?

    在微服务架构中,各个服务都是独立的部署单元,拥有各自的内存空间。如同上述摘要所述,直接通过静态变量在不同的微服务之间共享数据是不可能的。 试图在一个微服务中设置静态变量的值,然后在另一个微服务中访问它,将会得到 null 或初始值,而不是之前设置的值。 这不是 Spring Boot 特有的问题,而…

    2026年9月25日 • 用户投稿
    100
  • Micronaut中动态数据结构的类型安全验证策略

    Micronaut中动态数据结构的类型安全验证策略Micronaut中动态数据结构的类型安全验证策略Micronaut中动态数据结构的类型安全验证策略Micronaut中动态数据结构的类型安全验证策略

    本文探讨了在Micronaut应用中,如何有效处理具有动态属性和类型依赖验证的类。通过引入多态接口、特化实现类以及自定义Jackson反序列化器,我们能够实现对复杂动态数据结构的类型安全解析与精细化验证,确保数据完整性和业务规则的正确执行。 动态数据结构的验证挑战 在现代微服务架构中,经常会遇到需要…

    2026年9月25日 • 用户投稿
    1000
  • 利用AWS Pinpoint高效发送注册验证码(OTP)教程

    利用AWS Pinpoint高效发送注册验证码(OTP)教程利用AWS Pinpoint高效发送注册验证码(OTP)教程利用AWS Pinpoint高效发送注册验证码(OTP)教程利用AWS Pinpoint高效发送注册验证码(OTP)教程

    本文旨在指导开发者如何高效利用AWS Pinpoint服务发送用户注册验证码(OTP),解决传统AWS SNS在处理动态、未预注册手机号时的局限性。我们将深入探讨Pinpoint作为首选方案的优势,提供具体实现步骤和代码示例,并分享最佳实践,确保OTP消息的可靠、快速送达。 理解注册验证码(OTP)…

    2026年9月25日 • 用户投稿
    100
  • sublime怎么让不同类型文件使用不同的缩进设置 _sublime不同文件缩进设置方法

    sublime怎么让不同类型文件使用不同的缩进设置 _sublime不同文件缩进设置方法sublime怎么让不同类型文件使用不同的缩进设置 _sublime不同文件缩进设置方法sublime怎么让不同类型文件使用不同的缩进设置 _sublime不同文件缩进设置方法sublime怎么让不同类型文件使用不同的缩进设置 _sublime不同文件缩进设置方法

    Sublime Text 可根据不同文件类型自动应用缩进设置,通过语法专属配置实现。1. 打开文件后点击右下角语法名称,选择 Open Syntax Specific Settings;2. 在配置文件中设置 tab_size 和 translate_tabs_to_spaces,如 Python …

    2026年9月25日 • 用户投稿
    100
  • VSCode怎样用调试启动参数自定义运行时环境变量 VSCode启动参数自定义环境变量的创新用法​

    vscode允许通过launch.json中的”env”属性直接设置环境变量,或使用”envfile”指定.env文件来加载变量。1. 直接在launch.json中定义”env”属性可为调试会话注入键值对形式的环境变量,适用于…

    2026年9月25日
    300
  • Hibernate/Spring Boot中复合主键与多对多关联的实现指南

    Hibernate/Spring Boot中复合主键与多对多关联的实现指南Hibernate/Spring Boot中复合主键与多对多关联的实现指南Hibernate/Spring Boot中复合主键与多对多关联的实现指南Hibernate/Spring Boot中复合主键与多对多关联的实现指南

    本教程详细阐述了在Spring Boot和Hibernate框架中,如何优雅地处理具有附加属性的多对多关系,特别是当连接表需要复合主键时。我们将通过构建一个用户电影评分系统为例,深入探讨@EmbeddedId、@Embeddable以及@OneToMany、@ManyToOne等JPA注解的实际应用…

    2026年9月25日 • 用户投稿
    100
  • sublime的goto symbol in project功能怎么用_sublime Goto Symbol in Project使用方法

    sublime的goto symbol in project功能怎么用_sublime Goto Symbol in Project使用方法sublime的goto symbol in project功能怎么用_sublime Goto Symbol in Project使用方法sublime的goto symbol in project功能怎么用_sublime Goto Symbol in Project使用方法sublime的goto symbol in project功能怎么用_sublime Goto Symbol in Project使用方法

    使用快捷键Ctrl+Shift+R(Win/Linux)或Cmd+Shift+R(Mac)可快速调用Goto Symbol in Project功能,通过搜索符号名称跳转到函数、类等定义位置,支持模糊匹配与实时过滤,需确保项目已添加至侧边栏且语法包正确安装以保证索引识别效果。 Sublime Tex…

    2026年9月25日 • 用户投稿
    200

发表回复

登录后才能评论
关注微信