How to resolve the algorithm Number names step by step in the Scala programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Number names step by step in the Scala programming language

Table of Contents

Problem Statement

Show how to spell out a number in English. You can use a preexisting implementation or roll your own, but you should support inputs up to at least one million (or the maximum value of your language's default bounded integer type, if that's less). Support for inputs other than positive integers (like zero, negative integers, and floating-point numbers) is optional.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Number names step by step in the Scala programming language

Source code in the scala programming language

import scala.annotation.tailrec
import scala.collection.parallel.ParSeq

/** Spells an English numeral longhand. The numbers are expressed using words.
 *
 *  The implementation goes up to 10<sup>69</sup>-1 and also supports negative and zero inputs.
 *
 *  @example longhand( 1234 )  // results in: "one thousand two hundred thirty-four".
 */
trait LongHand {
  /** Spells a number longhand
   *
   *  Done by recursively process the triplets of decimal numbers.
   *  @param numeral		the numeric value to be converted
   *  @param showAnd		flag the output extra and in output, default off
   *  @param zeroString		the word for 0, default to "zero"
   *  @param showHyphen		hyphenate all compound numbers e.g. twenty-four, default is on
   *  @return				the numeric value expressed in words
   */
  def longhand(numeral: BigInt,
               showAnd: Boolean = false,
               zeroString: String = "zero",
               showHyphen: Boolean = true): String = {

    val condAndString = if (showAnd) "and " else ""
    val condHyphenString = if (showHyphen) "-" else " "

    // 234 Becomes "two hundred [and] thirty-four"
    def composeScale(nnn: String, isLSDgroup: Boolean, strE3: String): String = {
      nnn match { // Rare exceptions confirms the rule
        case "000" => ""
        case "100" => onesAndTeens(1) + hundredString + strE3 // Solves the faulty hundred AND thousand problem
        case _ => {
          val eval = (nnn.par.map(_.toString.toInt).reverse zip ParSeq('units, 'tens, 'hundreds)).reverse

          eval.map {
            case (d, 'units) if eval.seq.contains(1, 'tens) => onesAndTeens(d + 10)
            case (d, 'units) if (isLSDgroup && nnn == "0") => zeroString
            case (d, 'units) => onesAndTeens(d)
            case (d, 'hundreds) if d > 0 => onesAndTeens(d) + hundredString + condAndString
            case (d, 'tens) if d > 1 && eval.seq.contains(0, 'units) => tens(d)
            case (d, 'tens) if d > 1 => tens(d) + condHyphenString //'
            case _ => ""
          }.mkString + strE3
        }
      }
    } // def composeScale(…

    def compose(n: BigInt): String = {
      // "1234" becomes List((1,"thousand"), (234, ""))
      val decGroups = n.toString.reverse.grouped(3).map(_.reverse).toSeq.par // Group into powers of thousands
      if (decGroups.size <= shortScale.size) // Detect overflow  
      { // Send per group section to composeScale
        @tailrec
        def iter(elems: Seq[(String, String)], acc: String): String = {
          elems match {
            case (group, powers) :: tail => {
              iter(tail, acc + composeScale(group, tail == Nil, powers))
            }
            case _ => acc
          }
        } // Group of decimals are accompanied with the short scale name.
        iter(decGroups.zip(shortScale).reverse.toList, "").mkString.trim
      } else "###.overflow.###"
    } // def compose(…

    // Here starts def longhand(…
    if (numeral < 0) "minus " + compose(-numeral) else compose(numeral)
  } // End def longhand(…

  private val onesAndTeens = {
    def dozen = "one two three four five six seven eight nine ten eleven twelve".split(' ').map(_ + " ").par
    def teens = "thir four fif six seven eigh nine".split(' ').map(_ + "teen ").par
    ParSeq("") ++ dozen ++ teens
  }

  private val tens = ParSeq("", "") ++
    ("twen thir for fif six seven eigh nine".split(' ')).map(_ + "ty")
  private final val hundredString = "hundred "
  private val shortScale = {
    def p1 = "m b tr quadr quint sext sept oct non dec".split(' ').map(_ + "illion ").par
    def p2 = "un duo tre quattuor quin sex septen octo novem ".split(' ').map(_ + "decillion ").par
    def p3 = "vigint cent".split(' ').map(_ + "illion ").par
    ParSeq("", "thousand ") ++ p1 ++ p2 ++ p3
  }
} // trait LongHand

object SpellNumber extends LongHand with App {
  // Main entry A little test...
  { // Anonymous ordered list as test set
    def testVal1 = BigInt("1" * 69)
    def testVal9 = BigInt(10).pow(69) - 1

    @tailrec // Series generator of 9, 98, 987, 9876 …
    def inner(counter: Int, elem: BigInt, testList: ParSeq[BigInt]): ParSeq[BigInt] = {
      if (counter < 20)
        inner(counter + 1, elem * 10 + (9 - (counter % 10)), testList ++ ParSeq(elem))
      else testList.par
    }
    inner(0, 0L, // Test values
      ParSeq(-Long.MaxValue, -1000000000, 12, 13, 19, 20, 21, 112, 1001, 1012, 1013,
        Long.MaxValue - 1, Long.MaxValue - 13, testVal1, testVal9)) ++
      (for (z <- 0 to 69) yield BigInt(10).pow(z)) // powers of ten

  }.seq.sorted.foreach(num => println(f"$num%+,80d -> ${longhand(numeral = num, showAnd = true)}"))
} // object SpellNumber @ line 110


import scala.collection.immutable.TreeMap

val NUMBERS = TreeMap(
  1 -> "one", 2 -> "two", 3 -> "three", 4 -> "four", 5 -> "five", 6 -> "six", 7 -> "seven", 8 -> "eight", 9 -> "nine",
  10 -> "ten", 11 -> "eleven", 12 -> "twelve", 13 -> "thirteen", 14 -> "fourteen", 15 -> "fifteen", 16 -> "sixteen",
  17 -> "seventeen", 18 -> "eighteen", 19 -> "nineteen", 20 -> "twenty", 30 -> "thirty", 40 -> "forty",
  50 -> "fifty", 60 -> "sixty", 70 -> "seventy", 80 -> "eighty", 90 -> "ninety"
)

val HUNDREDS = TreeMap(
  100l -> "hundred", 1000l -> "thousand", 1000000l -> "million", 1000000000l -> "billion", 1000000000000l -> "trillion"
)

def numberToString(number: Long) : String = {
  if (HUNDREDS.to(number).nonEmpty) {
    val (h, hundreds) = HUNDREDS.to(number).last
    val remainder = number % h
    numberToString(number / h) + hundreds + {if (remainder > 0) {if (remainder < 100) " and " else ", "} + numberToString(remainder) else " "}
  } else if (NUMBERS.to(number.toInt).nonEmpty) {
    val (n, word) = NUMBERS.to(number.toInt).last
    val remainder = number - n
    word + {if (remainder > 0 && remainder < 10) "-" else " "} + numberToString(remainder)
  } else {
    ""
  }
}


  

You may also check:How to resolve the algorithm Truncate a file step by step in the PicoLisp programming language
You may also check:How to resolve the algorithm Heronian triangles step by step in the Raku programming language
You may also check:How to resolve the algorithm Write to Windows event log step by step in the Clojure programming language
You may also check:How to resolve the algorithm Apply a callback to an array step by step in the Clojure programming language
You may also check:How to resolve the algorithm MD5 step by step in the Sidef programming language