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罗马数字转换:for…in循环与对象属性迭代顺序解析_创想鸟

JavaScript罗马数字转换:for…in循环与对象属性迭代顺序解析

JavaScript罗马数字转换:for...in循环与对象属性迭代顺序解析

本文深入探讨JavaScript中将十进制数转换为罗马数字时,因for…in循环对对象属性迭代顺序的特殊处理而导致的常见问题。我们将分析为何使用数字作为键的查找表会导致错误,而字符串键则能正确工作,并提供最佳实践以确保算法的准确性。

罗马数字转换的贪心算法原理

将十进制数字转换为罗马数字通常采用贪心算法。其核心思想是,从最大的罗马数字值开始,不断减去当前数字中能匹配的最大罗马数字,并将其对应的罗马字符追加到结果字符串中,直到原始数字变为零。例如,要转换数字 9,我们应该优先匹配 ix (9),而不是先匹配 v (5) 再匹配 i (1) 四次。因此,罗马数字与十进制值的映射表必须按照十进制值从大到小排列,以确保贪心策略的正确性。

遇到问题:for…in循环与对象键序

在JavaScript中实现上述贪心算法时,开发者常会使用一个对象作为查找表来存储罗马数字及其对应的十进制值。然而,当这些十进制值被用作对象的键时,可能会遇到意想不到的行为。

考虑以下两种实现尝试:

尝试一:使用十进制数作为键(导致失败)

function convertToRoman_Failing(num) {  const romanNumerals = {    1000: "M",    900: "CM",    500: "D",    400: "CD",    100: "C",    90: "XC",    50: "L",    40: "XL",    10: "X",    9: "IX",    5: "V",    4: "IV",    1: "I"  };  let roman = "";  let restartLoop = false;  do {    restartLoop = false;    for (let key in romanNumerals) { // 问题出在这里      // key 是字符串形式的数字,如 "1", "4", "5"      if (num >= parseInt(key)) {         roman += romanNumerals[key];        num -= parseInt(key);        restartLoop = true;        break;      }    }  } while (restartLoop);  return roman;}console.log("失败示例:");console.log(`convertToRoman_Failing(3): ${convertToRoman_Failing(3)}`); // 预期: III, 实际: III (正确)console.log(`convertToRoman_Failing(4): ${convertToRoman_Failing(4)}`); // 预期: IV, 实际: IIII (错误)console.log(`convertToRoman_Failing(9): ${convertToRoman_Failing(9)}`); // 预期: IX, 实际: VIIII (错误)console.log(`convertToRoman_Failing(23): ${convertToRoman_Failing(23)}`); // 预期: XXIII, 实际: XXIII (正确)

上述代码在转换 4 或 9 等数字时会产生错误的结果。例如,对于 4,它会输出 IIII 而不是 IV。这是因为 for…in 循环并未按照我们在 romanNumerals 对象中定义的顺序(从大到小)遍历键。

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

核心原因:JavaScript for…in 循环的属性迭代顺序

根据 ECMAScript 规范,for…in 循环在遍历对象属性时,其顺序是明确定义的:

首先遍历所有非负整数键(可以作为数组索引的键),并按照数值升序排列。然后遍历所有其他字符串键,按照它们被添加到对象中的时间顺序(或更复杂的内部规则)升序排列。

在 convertToRoman_Failing 函数中,romanNumerals 对象的键是 1000, 900, 500 等十进制数字。当JavaScript引擎处理这些键时,它会将它们识别为整数键(即使它们在代码中看起来是数字字面量,在作为对象键时会被隐式转换为字符串)。因此,for…in 循环会先遍历 1,然后 4,5,9,10,以此类推,最终遍历到 1000。

这意味着,当 num 为 4 时,循环首先遇到键 1。由于 4 >= 1,它会添加 I 并将 num 减为 3。这个过程会重复四次,最终得到 IIII。这违背了贪心算法应优先匹配最大可能值的原则。

为了更直观地理解,可以运行以下代码:

const highToLow = {  1000: "M",  900: "CM",  500: "D",  400: "CD",  100: "C",  90: "XC",  50: "L",  40: "XL",  10: "X",  9: "IX",  5: "V",  4: "IV",  1: "I"};for (let key in highToLow) {  console.log(`键: ${key}, 值: ${highToLow[key]}`);}// 输出顺序将是:// 键: 1, 值: I// 键: 4, 值: IV// 键: 5, 值: V// 键: 9, 值: IX// 键: 10, 值: X// ...// 键: 1000, 值: M

尝试二:使用罗马数字字符串作为键(成功)

function convertToRoman_Working(num) {  const romanNumerals = {    "M": 1000,    "CM": 900,    "D": 500,    "CD": 400,    "C": 100,    "XC": 90,    "L": 50,    "XL": 40,    "X": 10,    "IX": 9,    "V": 5,    "IV": 4,    "I": 1  };  let roman = "";  let restartLoop = false;  do {    restartLoop = false;    for (let key in romanNumerals) { // 这里的key是字符串,如 "M", "CM"      if (num >= romanNumerals[key]) { // 比较的是值        roman += key;        num -= romanNumerals[key];        restartLoop = true;        break;      }    }  } while (restartLoop);  return roman;}console.log("n成功示例:");console.log(`convertToRoman_Working(3): ${convertToRoman_Working(3)}`); // 预期: III, 实际: IIIconsole.log(`convertToRoman_Working(4): ${convertToRoman_Working(4)}`); // 预期: IV, 实际: IVconsole.log(`convertToRoman_Working(9): ${convertToRoman_Working(9)}`); // 预期: IX, 实际: IXconsole.log(`convertToRoman_Working(23): ${convertToRoman_Working(23)}`); // 预期: XXIII, 实际: XXIII

在这个成功的示例中,romanNumerals 对象的键是 “M”, “CM”, “D” 等罗马数字字符串。这些键不属于“非负整数键”范畴,因此它们的迭代顺序通常会遵循它们在对象中被定义的顺序(即创建顺序),这恰好符合我们从大到小进行匹配的需求。

最佳实践与更健壮的实现

虽然第二种方法有效,但依赖于 for…in 对非整数键的“创建顺序”行为,在某些极端情况下(例如,如果对象属性被删除后重新添加)可能不是百分之百可靠。为了确保查找表的顺序始终按照预期,最佳实践是使用一个数组来存储罗马数字映射,因为数组的元素顺序是明确且可控的。

以下是一个更健壮的实现,它使用一个包含对象字面量的数组:

function convertToRoman_Robust(num) {  const romanNumeralsMap = [    { value: 1000, numeral: "M" },    { value: 900, numeral: "CM" },    { value: 500, numeral: "D" },    { value: 400, numeral: "CD" },    { value: 100, numeral: "C" },    { value: 90, numeral: "XC" },    { value: 50, numeral: "L" },    { value: 40, numeral: "XL" },    { value: 10, numeral: "X" },    { value: 9, numeral: "IX" },    { value: 5, numeral: "V" },    { value: 4, numeral: "IV" },    { value: 1, numeral: "I" }  ];  let roman = "";  for (const entry of romanNumeralsMap) {    while (num >= entry.value) {      roman += entry.numeral;      num -= entry.value;    }  }  return roman;}console.log("n健壮实现示例:");console.log(`convertToRoman_Robust(3): ${convertToRoman_Robust(3)}`);console.log(`convertToRoman_Robust(4): ${convertToRoman_Robust(4)}`);console.log(`convertToRoman_Robust(9): ${convertToRoman_Robust(9)}`);console.log(`convertToRoman_Robust(23): ${convertToRoman_Robust(23)}`);console.log(`convertToRoman_Robust(3999): ${convertToRoman_Robust(3999)}`); // MMMCMXCIX

在这个健壮的实现中:

我们使用一个 romanNumeralsMap 数组,其中每个元素都是一个包含 value 和 numeral 属性的对象。for…of 循环用于遍历数组,确保了迭代顺序严格按照数组元素的定义顺序。内部的 while 循环实现了贪心匹配,只要当前数字 num 大于或等于当前罗马数字的 value,就持续追加对应的 numeral 并减去 value。

这种方法消除了对对象属性迭代顺序的任何潜在依赖,使得代码更加清晰、可预测且易于维护。

总结

在JavaScript中处理需要特定顺序的查找表时,尤其是在使用贪心算法的场景下,理解 for…in 循环对对象属性迭代顺序的特殊规则至关重要。将数字作为对象键可能导致它们被自动排序,从而破坏预期的逻辑。为了避免此类问题,推荐使用数组(例如,包含对象字面量的数组)来存储有序的映射关系,并通过 for…of 循环进行迭代,以确保算法的准确性和健壮性。

以上就是JavaScript罗马数字转换:for…in循环与对象属性迭代顺序解析的详细内容,更多请关注创想鸟其它相关文章!

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

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Django电商项目中AJAX动态加载产品列表图片不显示的解决方案
上一篇 2025年12月20日 19:36:17
解决CSS布局中父元素高度不随子元素内容自适应的问题
下一篇 2025年12月20日 19:36:29

相关推荐

  • Java Stream API处理嵌套对象字段求和:以购物车条目为例

    Java Stream API处理嵌套对象字段求和:以购物车条目为例Java Stream API处理嵌套对象字段求和:以购物车条目为例Java Stream API处理嵌套对象字段求和:以购物车条目为例Java Stream API处理嵌套对象字段求和:以购物车条目为例

    本文深入探讨如何利用Java Stream API高效地对复杂嵌套对象中的数值字段进行聚合求和。通过一个购物车条目的具体案例,演示了如何从多层级对象中提取并累加BigDecimal类型的费用数据,强调了mapToDouble、BigDecimal的精确计算以及在处理可能为空的字段时,结合注解进行nu…

    2026年9月27日 • 用户投稿
    000
  • Stripe Webhook签名验证错误解析与中间件顺序优化

    Stripe Webhook签名验证错误解析与中间件顺序优化Stripe Webhook签名验证错误解析与中间件顺序优化Stripe Webhook签名验证错误解析与中间件顺序优化Stripe Webhook签名验证错误解析与中间件顺序优化

    Stripe Webhook签名验证时出现”Payload must be provided as a string or a Buffer”错误,通常是由于Express应用中全局express.json()中间件过早解析了原始请求体。本文将深入解析此问题,并提供通过调整中…

    2026年9月27日 • 用户投稿
    000
  • OpenAI 推出全新 AI 功能 ChatGPT Pulse

    OpenAI 推出全新 AI 功能 ChatGPT PulseOpenAI 推出全新 AI 功能 ChatGPT PulseOpenAI 推出全新 AI 功能 ChatGPT PulseOpenAI 推出全新 AI 功能 ChatGPT Pulse

    openai 宣布上线全新功能 chatgpt pulse,标志着 chatgpt 正式从被动响应式对话工具进化为具备主动服务能力的个性化助手。该功能目前以预览版本的形式率先登陆移动端,仅对 pro 订阅用户(每月 200 美元)开放使用权限。 据官方介绍,Pulse 是 ChatGPT 全新打造的…

    2026年9月27日 • 用户投稿
    100
  • windows怎么查看电脑支持的内存大小 windows查看电脑最大支持内存方法

    windows怎么查看电脑支持的内存大小 windows查看电脑最大支持内存方法windows怎么查看电脑支持的内存大小 windows查看电脑最大支持内存方法windows怎么查看电脑支持的内存大小 windows查看电脑最大支持内存方法windows怎么查看电脑支持的内存大小 windows查看电脑最大支持内存方法

    首先通过命令提示符输入wmic memphysical get maxcapacity获取主板最大支持内存,再结合CPU-Z等工具或官网规格确认具体参数,最后用任务管理器查看插槽使用情况以规划升级方案。 如果您计划升级电脑内存,但不确定主板或系统最大支持多大的内存容量,则需要准确查询硬件的限制。以下…

    2026年9月27日 • 用户投稿
    100
  • mysql中explain用法

    mysql中explain用法mysql中explain用法mysql中explain用法mysql中explain用法

    MySQL中的EXPLAIN用法详解及代码示例 在MySQL中,EXPLAIN是一个非常有用的工具,用于分析查询语句的执行计划。通过使用EXPLAIN,我们可以了解到MySQL数据库是如何执行查询语句的,从而帮助我们优化查询性能。 EXPLAIN的基本语法如下: EXPLAIN SELECT 列名 …

    2026年9月27日 • 用户投稿
    200
  • sublime怎么设置在按下回车时自动缩进_sublime按回车自动缩进设置

    sublime怎么设置在按下回车时自动缩进_sublime按回车自动缩进设置sublime怎么设置在按下回车时自动缩进_sublime按回车自动缩进设置sublime怎么设置在按下回车时自动缩进_sublime按回车自动缩进设置sublime怎么设置在按下回车时自动缩进_sublime按回车自动缩进设置

    确保”auto_indent”: true已启用,使新行继承上一行缩进;2. 检查并正确设置文件语法类型,确保语言识别无误;3. 推荐配置”translate_tabs_to_spaces”: true和”tab_size”: …

    2026年9月27日 • 用户投稿
    200
  • JScrollPane滚动条自动更新行为的控制策略与实践

    JScrollPane滚动条自动更新行为的控制策略与实践JScrollPane滚动条自动更新行为的控制策略与实践JScrollPane滚动条自动更新行为的控制策略与实践JScrollPane滚动条自动更新行为的控制策略与实践

    本教程详细探讨如何有效控制JScrollPane的滚动条自动更新行为,特别是在内容重绘后避免意外滚动。文章重点介绍通过设置滚动条策略(如ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)来禁用滚动条或其自动更新,并简要提及Viewport尺寸调整的替代方法…

    2026年9月27日 • 用户投稿
    000
  • C# .NET中基于JWT和外部授权服务器的REST API安全配置指南

    C# .NET中基于JWT和外部授权服务器的REST API安全配置指南C# .NET中基于JWT和外部授权服务器的REST API安全配置指南C# .NET中基于JWT和外部授权服务器的REST API安全配置指南C# .NET中基于JWT和外部授权服务器的REST API安全配置指南

    本文旨在提供一个简洁明了的教程,指导开发者如何在C# .NET应用中,以纯资源服务器模式,通过外部授权服务器(如AWS Cognito或Asgardeo)实现REST API的安全保护。文章将重点介绍如何利用JWT Bearer认证机制,通过最小化配置,快速构建一个能够验证传入访问令牌的API服务,…

    2026年9月27日 • 用户投稿
    100
  • Codename One:实现安全的数字密码输入框

    Codename One:实现安全的数字密码输入框Codename One:实现安全的数字密码输入框Codename One:实现安全的数字密码输入框Codename One:实现安全的数字密码输入框

    本文详细介绍了在Codename One中创建既能接受纯数字输入又能进行密码遮罩的文本输入框的方法。通过使用位或运算符(|)组合TextArea.NUMERIC和TextArea.PASSWORD约束,可以有效地实现这一需求,避免了链式调用constraint()的常见误区,从而提升用户体验和输入安…

    2026年9月27日 • 用户投稿
    100
  • 苹果 A19 芯片内部特写:架构微调带来能效提升

    苹果 A19 芯片内部特写:架构微调带来能效提升苹果 A19 芯片内部特写:架构微调带来能效提升苹果 A19 芯片内部特写:架构微调带来能效提升苹果 A19 芯片内部特写:架构微调带来能效提升

    苹果最新一代的a19芯片在芯片制造工艺方面较a18有显著提升,近期一组显微照片首次揭示了iphone 17系列最新芯片的内部细节。 本次随iPhone 17发布亮相的A19及A19 Pro芯片,是苹果自研芯片设计的又一进步。尽管苹果方面针对性能提升作出多项官方承诺,但由ChipWise团队拍摄的So…

    2026年9月27日 • 用户投稿
    200
  • 豆包AI如何实现智能排版 豆包AI文档自动格式化功能

    豆包AI提供的智能排版功能,能够显著提升文档处理效率。本文将详细介绍如何利用豆包AI的文档自动格式化能力,解决文档排版耗时的问题。我们将逐步解析使用该功能的过程,包括如何启用、输入内容以及完成格式化,以便用户能够轻松掌握并应用。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 …

    2026年9月27日
    100
  • Java Swing GUI:构建交互式逻辑门(AND门示例)

    Java Swing GUI:构建交互式逻辑门(AND门示例)Java Swing GUI:构建交互式逻辑门(AND门示例)Java Swing GUI:构建交互式逻辑门(AND门示例)Java Swing GUI:构建交互式逻辑门(AND门示例)

    本文详细介绍了如何使用Java Swing构建一个简单的AND逻辑门GUI应用。通过结合JCheckBox作为输入和JLabel作为视觉输出,并利用ChangeListener监听组件状态变化,实现当两个复选框都被选中时显示“绿色”,否则显示“红色”的功能。教程涵盖了组件创建、事件监听以及将自定义面…

    2026年9月27日 • 用户投稿
    100
  • AI Overviews如何设置智能告警 AI Overviews异常检测阈值

    AI Overviews如何设置智能告警 AI Overviews异常检测阈值AI Overviews如何设置智能告警 AI Overviews异常检测阈值AI Overviews如何设置智能告警 AI Overviews异常检测阈值AI Overviews如何设置智能告警 AI Overviews异常检测阈值

    本文将详细指导您如何在AI Overviews中设置智能告警以及调整异常检测阈值,帮助您及时发现并响应潜在问题。我们将分步骤讲解具体操作过程,确保您能够顺利配置这些关键功能,从而实现更主动、更精准的系统监控。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R…

    2026年9月27日 • 用户投稿
    000
  • 曝华为Mate80系列新增Air机型 支持eSIM 采用微泵液

    曝华为Mate80系列新增Air机型 支持eSIM 采用微泵液曝华为Mate80系列新增Air机型 支持eSIM 采用微泵液曝华为Mate80系列新增Air机型 支持eSIM 采用微泵液曝华为Mate80系列新增Air机型 支持eSIM 采用微泵液

    9月24日,cnmo获悉,有数码博主透露了华为mate80 pro+的部分配置详情。据消息显示,该机型顶配版将配备6000mah大容量电池,搭配24gb运行内存与2tb机身存储。此外,华为mate80系列将新增一款air版本,采用创新的微泵液冷技术(无风扇设计),并支持esim功能。 华为Mate …

    2026年9月27日 • 用户投稿
    100
  • 360极速浏览器收藏夹栏怎么显示_360极速浏览器显示或隐藏书签栏的方法

    360极速浏览器收藏夹栏怎么显示_360极速浏览器显示或隐藏书签栏的方法360极速浏览器收藏夹栏怎么显示_360极速浏览器显示或隐藏书签栏的方法360极速浏览器收藏夹栏怎么显示_360极速浏览器显示或隐藏书签栏的方法360极速浏览器收藏夹栏怎么显示_360极速浏览器显示或隐藏书签栏的方法

    360极速浏览器书签栏未显示时,可通过快捷键Ctrl+Shift+B切换,或在菜单“工具”中点击“显示书签栏”,也可在“设置-外观”中开启默认显示。 如果您希望在浏览网页时快速访问常用网站,但发现360极速浏览器的收藏夹栏未显示,可能是书签栏被隐藏了。以下是恢复显示书签栏的操作方法。 本文运行环境:…

    2026年9月27日 • 用户投稿
    100
  • Java Swing 实现带复选框和图像的逻辑门

    Java Swing 实现带复选框和图像的逻辑门Java Swing 实现带复选框和图像的逻辑门Java Swing 实现带复选框和图像的逻辑门Java Swing 实现带复选框和图像的逻辑门

    本文介绍了如何使用 Java Swing 创建一个简单的 AND 逻辑门 GUI,该 GUI 包含两个复选框和一个图像。当两个复选框都被选中时,图像变为绿色;否则,图像变为红色。我们将使用 JCheckBox、JLabel 和 ChangeListener 来实现这一功能,并提供完整的代码示例。 创…

    2026年9月27日 • 用户投稿
    000
  • Perplexity AI如何实现考古鉴定 Perplexity AI文物真伪辨别

    Perplexity AI如何实现考古鉴定 Perplexity AI文物真伪辨别Perplexity AI如何实现考古鉴定 Perplexity AI文物真伪辨别Perplexity AI如何实现考古鉴定 Perplexity AI文物真伪辨别Perplexity AI如何实现考古鉴定 Perplexity AI文物真伪辨别

    本文将探讨 Perplexity AI 在考古鉴定和文物真伪辨别中扮演的角色。我们将详细讲解如何利用这一工具辅助考古研究人员和鉴定专家进行初步的信息检索和分析,为文物的真伪判断提供参考依据。文章会分步骤指导用户如何操作,以便更好地理解和应用 Perplexity AI 的功能。 ☞☞☞AI 智能聊天…

    2026年9月27日 • 用户投稿
    100
  • windows怎么用命令提示符_Windows命令提示符(CMD)常用命令大全

    windows怎么用命令提示符_Windows命令提示符(CMD)常用命令大全windows怎么用命令提示符_Windows命令提示符(CMD)常用命令大全windows怎么用命令提示符_Windows命令提示符(CMD)常用命令大全windows怎么用命令提示符_Windows命令提示符(CMD)常用命令大全

    通过CMD可高效执行IP查询、网络测试、DNS清理、目录管理、文件操作、系统信息查看及关机控制等任务,提升Windows系统操作效率。 如果您需要在Windows系统中执行各种文件管理、系统诊断或网络配置任务,使用命令提示符(CMD)可以高效地完成这些操作。通过输入特定命令,您可以直接与操作系统交互…

    2026年9月27日 • 用户投稿
    000
  • 多模态AI如何处理雷达信号 多模态AI目标跟踪技术

    多模态AI如何处理雷达信号 多模态AI目标跟踪技术多模态AI如何处理雷达信号 多模态AI目标跟踪技术多模态AI如何处理雷达信号 多模态AI目标跟踪技术多模态AI如何处理雷达信号 多模态AI目标跟踪技术

    本文将详细阐述多模态AI如何有效处理雷达信号,并将其应用于目标跟踪技术。我们将从雷达信号的基础处理入手,逐步讲解如何将雷达数据融入多模态AI框架,并通过分步骤的方式解析AI进行目标跟踪的具体过程。这将帮助读者理解多模态AI在复杂环境中利用雷达数据的强大能力。 ☞☞☞AI 智能聊天, 问答助手, AI…

    2026年9月27日 • 用户投稿
    000
  • Java:子类如何在不修改父类的情况下,通过重写方法间接利用父类私有成员

    Java:子类如何在不修改父类的情况下,通过重写方法间接利用父类私有成员Java:子类如何在不修改父类的情况下,通过重写方法间接利用父类私有成员Java:子类如何在不修改父类的情况下,通过重写方法间接利用父类私有成员Java:子类如何在不修改父类的情况下,通过重写方法间接利用父类私有成员

    在Java中,当子类需要在不修改父类的前提下,利用父类的私有成员时,直接访问是不允许的。本教程将展示如何通过调用父类的公共或保护方法(例如super.toString()),来间接利用父类内部已处理过的私有数据,尤其适用于重写方法并在此基础上扩展功能的情景。 Java封装性与私有成员:理解限制 ja…

    2026年9月27日 • 用户投稿
    000

发表回复

登录后才能评论
关注微信