简体   繁体   English

在函数递归期间维护字符串变量-JavaScript

[英]Maintaining String Variable during Function Recursions - JavaScript

I've created a simple function that is supposed to translate a number into a Roman Numeral. 我创建了一个简单的函数,该函数应该将数字转换为罗马数字。 It appears that everything is working properly except one thing. 似乎除了一件事之外,其他所有东西都正常工作。

Through every recursion in my code, the string that holds the roman numerals is reset to "". 通过代码中的每次递归,保存罗马数字的字符串将重置为“”。

What is the best practice for maintaining variables like this through recursions in a function? 通过函数中的递归维护此类变量的最佳实践是什么?

I tried declaring variable romanStr = "" in the global scope, and removing the conditional declaration within the program, and of course that worked. 我尝试在全局范围内声明变量romanStr =“”,并删除程序中的条件声明,当然这是可行的。 I however know that is the worst practice. 但是,我知道这是最糟糕的做法。

For example, take the number 1234, which converted into roman numerals is "MCCXXXIV". 例如,将数字1234转换为罗马数字是“ MCCXXXIV”。 My program will only return "IV", the result of the last recursion. 我的程序将仅返回“ IV”,这是最后一次递归的结果。

 function convertToRoman(num) { console.log(`START FUNCTION FROM THE BEGINNING`); console.log(`current num: ${num}`); if (typeof romanStr === "undefined") { var romanStr = ""; } const bNumbers = [1000, 500, 100, 50, 10, 5, 1]; const romanSymbols = { 0: ["M"], 2: ["C", "D", "M"], 4: ["X", "L", "C"], 6: ["I", "V", "X"] }; const arraySelector = arrNum => num >= arrNum; let symbolSetIndex = bNumbers.findIndex(arraySelector); console.log(`symbolSetIndex: ${symbolSetIndex}`); let symbolSet = romanSymbols[symbolSetIndex]; console.log(`symbolSet: [${symbolSet}]`); let numString = num.toString(); let numeral = parseInt(numString[0]); console.log(`numeral: ${numeral}`); let nextNum = parseInt(numString.substr(1)); console.log(`nextNum: ${nextNum}`); // CONDITIONAL STATEMENTS // if (symbolSetIndex === 0) { for (let i = 1; i <= numeral; i++) { romanStr = `${romanStr}${symbolSet[0]}`; } return convertToRoman(nextNum); } if (numeral < 4) { for (let i = 1; i <= numeral; i++) { romanStr = `${romanStr}${symbolSet[0]}`; } } if (numeral === 4) { romanStr = `${romanStr}${symbolSet[0]}${symbolSet[1]}`; } if (numeral === 5) { romanStr = `${romanStr}${symbolSet[1]}`; } if (numeral === 6) { romanStr = `${romanStr}${symbolSet[1]}${symbolSet[0]}`; } if (numeral > 6) { romanStr = `${romanStr}${symbolSet[1]}`; // requires the 5 numeral first for (let i = 1; i <= numeral - 6; i++) { romanStr = `${romanStr}${symbolSet[0]}`; } } if (numeral === 9) { romanStr = `${romanStr}${symbolSet[2]}${symbolSet[1]}`; } if (numString.length === 1) { return romanStr; } return convertToRoman(nextNum); } console.log(convertToRoman(5214)); 

You don't need to keep the variable through all the calls. 您无需在所有调用中都保留变量。 Concatenate the current value to the value returned by the recursion. 将当前值连接到递归返回的值。

 function convertToRoman(num) { console.log(`START FUNCTION FROM THE BEGINNING`); console.log(`current num: ${num}`); var romanStr; const bNumbers = [1000, 500, 100, 50, 10, 5, 1]; const romanSymbols = { 0: ["M"], 2: ["C", "D", "M"], 4: ["X", "L", "C"], 6: ["I", "V", "X"] }; const arraySelector = arrNum => num >= arrNum; let symbolSetIndex = bNumbers.findIndex(arraySelector); console.log(`symbolSetIndex: ${symbolSetIndex}`); let symbolSet = romanSymbols[symbolSetIndex]; console.log(`symbolSet: [${symbolSet}]`); let numString = num.toString(); let numeral = parseInt(numString[0]); console.log(`numeral: ${numeral}`); let nextNum = parseInt(numString.substr(1)); console.log(`nextNum: ${nextNum}`); // CONDITIONAL STATEMENTS // if (symbolSetIndex === 0) { for (let i = 1; i <= numeral; i++) { romanStr = `${romanStr}${symbolSet[0]}`; } return romanStr + convertToRoman(nextNum); } if (numeral < 4) { for (let i = 1; i <= numeral; i++) { romanStr = `${romanStr}${symbolSet[0]}`; } } if (numeral === 4) { romanStr = `${romanStr}${symbolSet[0]}${symbolSet[1]}`; } if (numeral === 5) { romanStr = `${romanStr}${symbolSet[1]}`; } if (numeral === 6) { romanStr = `${romanStr}${symbolSet[1]}${symbolSet[0]}`; } if (numeral > 6) { romanStr = `${romanStr}${symbolSet[1]}`; // requires the 5 numeral first for (let i = 1; i <= numeral - 6; i++) { romanStr = `${romanStr}${symbolSet[0]}`; } } if (numeral === 9) { romanStr = `${romanStr}${symbolSet[2]}${symbolSet[1]}`; } if (numString.length === 1) { return romanStr; } return romanStr + convertToRoman(nextNum); } console.log(convertToRoman(5214)); 

Recursion is a functional heritage and so using it with functional style will yield the best results. 递归是一种功能性遗产,因此将其与功能性样式一起使用将产生最佳效果。 The Roman Numeral algorithm was one of those things that really blew my mind when I first saw it expressed in functional style: CodeReview.SE: Converting to Roman Numerals . 当我第一次看到它以功能风格表示时,Roman Numeral算法确实让我大吃一惊:CodeReview.SE:转换为Roman Numerals

@sdcvvc provides a beautiful encoding @sdcvvc提供了漂亮的编码

toRoman :: Integer -> String
toRoman 0 = "N"
toRoman x | x > 0 = snd $ foldl f (x,[]) convMap
  where f (n,s) (rn, rs) = (l, s ++ concat (genericReplicate k rs))
              where (k,l) = divMod n rn

The simplicity is truly astonishing. 简单性真是令人惊讶。 I cannot take credit for any part of the algorithm provided above, but I can translate it into JavaScript for you. 我不能相信上面提供的算法的任何部分,但是可以为您翻译成JavaScript。

I share this because it shows you a way to approach your problem from a completely different angle. 我同意这一点,因为它向您展示了一种从完全不同的角度解决问题的方法。 The other answers provided on the CodeReview thread provide even further insight. CodeReview线程上提供的其他答案甚至提供了进一步的见解。 I highly encourage you to check them out :D 我强烈建议您检查一下:D

 const divMod = (n, d, k) => k (n / d >> 0, n % d) const foldl = (f, init, xs) => xs.reduce (f, init) const replicate = (n, s) => s.repeat (n) const snd = ([ _, x ]) => x const convMap = [ [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"] ] const toRoman = (x = 0) => x === 0 ? "N" : snd ( foldl ( ([ n, s ], [ rn, rs ]) => divMod (n, rn, (k, l) => [ l, s + replicate (k, rs) ]) , [ x, [] ] , convMap ) ) console.log ( toRoman (0) // N , toRoman (7) // VII , toRoman (66) // LXVI , toRoman (99) // XCIX , toRoman (1984) // MCMLXXXIV ) 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM