Four is the number of letters in the ...: Difference between revisions

From Rosetta Code
Content added Content deleted
(added a missing header for REXX.)
(Added Kotlin)
Line 59: Line 59:
<br><br>
<br><br>


=={{header|Kotlin}}==
This pulls in (slightly adjusted) code from related tasks to convert numbers to text or ordinals.

Although it's not actually part of the current task, my sentence lengths for n >= 1000 (but not for n == 201) are somewhat lower than those of the REXX entry. I have not been able to figure out why.
<lang scala>// version 1.1.4-3

val names = mapOf(
1 to "one",
2 to "two",
3 to "three",
4 to "four",
5 to "five",
6 to "six",
7 to "seven",
8 to "eight",
9 to "nine",
10 to "ten",
11 to "eleven",
12 to "twelve",
13 to "thirteen",
14 to "fourteen",
15 to "fifteen",
16 to "sixteen",
17 to "seventeen",
18 to "eighteen",
19 to "nineteen",
20 to "twenty",
30 to "thirty",
40 to "forty",
50 to "fifty",
60 to "sixty",
70 to "seventy",
80 to "eighty",
90 to "ninety"
)
val bigNames = mapOf(
1_000L to "thousand",
1_000_000L to "million",
1_000_000_000L to "billion",
1_000_000_000_000L to "trillion",
1_000_000_000_000_000L to "quadrillion",
1_000_000_000_000_000_000L to "quintillion"
)

val irregOrdinals = mapOf(
"one" to "first",
"two" to "second",
"three" to "third",
"five" to "fifth",
"eight" to "eighth",
"nine" to "ninth",
"twelve" to "twelfth"
)
fun String.toOrdinal(): String {
if (this == "zero") return "zeroth" // or alternatively 'zeroeth'
val splits = this.split(' ', '-')
var last = splits[splits.lastIndex]
return if (irregOrdinals.containsKey(last)) this.dropLast(last.length) + irregOrdinals[last]!!
else if (last.endsWith("y")) this.dropLast(1) + "ieth"
else this + "th"
}

fun numToText(n: Long, uk: Boolean = false): String {
if (n == 0L) return "zero"
val neg = n < 0L
val maxNeg = n == Long.MIN_VALUE
var nn = if (maxNeg) -(n + 1) else if (neg) -n else n
val digits3 = IntArray(7)
for (i in 0..6) { // split number into groups of 3 digits from the right
digits3[i] = (nn % 1000).toInt()
nn /= 1000
}

fun threeDigitsToText(number: Int) : String {
val sb = StringBuilder()
if (number == 0) return ""
val hundreds = number / 100
val remainder = number % 100
if (hundreds > 0) {
sb.append(names[hundreds], " hundred")
if (remainder > 0) sb.append(if (uk) " and " else " ")
}
if (remainder > 0) {
val tens = remainder / 10
val units = remainder % 10
if (tens > 1) {
sb.append(names[tens * 10])
if (units > 0) sb.append("-", names[units])
}
else sb.append(names[remainder])
}
return sb.toString()
}

val strings = Array<String>(7) { threeDigitsToText(digits3[it]) }
var text = strings[0]
var andNeeded = uk && digits3[0] in 1..99
var big = 1000L
for (i in 1..6) {
if (digits3[i] > 0) {
var text2 = strings[i] + " " + bigNames[big]
if (text.length > 0) {
text2 += if (andNeeded) " and " else " " // no commas inserted in this version
andNeeded = false
}
else andNeeded = uk && digits3[i] in 1..99
text = text2 + text
}
big *= 1000
}
if (maxNeg) text = text.dropLast(5) + "eight"
if (neg) text = "minus " + text
return text
}

val opening = "Four is the number of letters in the first word of this sentence,".split(' ')

val String.adjustedLength get() = this.replace(",", "").replace("-", "").length // no ',' or '-'

fun getWords(n: Int): List<String> {
val words = mutableListOf<String>()
words.addAll(opening)
if (n > opening.size) {
var k = 2
while (true) {
val len = words[k - 1].adjustedLength
val text = numToText(len.toLong())
val splits = text.split(' ')
words.addAll(splits)
if (words.size >= n) break
words.add("in")
if (words.size == n) break
words.add("the")
if (words.size == n) break
val text2 = numToText(k.toLong()).toOrdinal() + "," // add trailing comma
val splits2 = text2.split(' ')
words.addAll(splits2)
if (words.size >= n) break
k++
}
}
return words.take(n)
}

fun getLengths(n: Int): Pair<List<Int>, Int> {
val words = getWords(n)
val lengths = words.map { it.adjustedLength }
val sentenceLength = words.sumBy { it.length } + n - 1 // includes hyphens, commas & spaces
return Pair(lengths, sentenceLength)
}

fun getLastWord(n: Int): Triple<String, Int, Int> {
val words = getWords(n)
val lastWord = words.last()
val lastWordLength = lastWord.adjustedLength
val sentenceLength = words.sumBy { it.length } + n - 1 // includes hyphens, commas & spaces
return Triple(lastWord, lastWordLength, sentenceLength)
}

fun main(args: Array<String>) {
var n = 201
println("The lengths of the first $n words are:\n")
val (list, sentenceLength) = getLengths(n)
for (i in 0 until n) {
if (i % 25 == 0) {
if (i > 0) println()
print("${"%3d".format(i + 1)}: ")
}
print("%3d".format(list[i]))
}
println("\n\nLength of sentence = $sentenceLength\n")
n = 1_000
do {
var (word, wLen, sLen) = getLastWord(n)
if (word.endsWith(",")) word = word.dropLast(1) // strip off any trailing comma
println("The length of word $n [$word] is $wLen")
println("Length of sentence = $sLen\n")
n *= 10
}
while (n <= 10_000_000)
}</lang>

{{out}}
<pre>
The lengths of the first 201 words are:

1: 4 2 3 6 2 7 2 3 5 4 2 4 8 3 2 3 6 5 2 3 5 3 2 3 6
26: 3 2 3 5 5 2 3 5 3 2 3 7 5 2 3 6 4 2 3 5 4 2 3 5 3
51: 2 3 8 4 2 3 7 5 2 3 10 5 2 3 10 3 2 3 9 5 2 3 9 3 2
76: 3 11 4 2 3 10 3 2 3 10 5 2 3 9 4 2 3 11 5 2 3 12 3 2 3
101: 11 5 2 3 12 3 2 3 11 5 2 3 11 3 2 3 13 5 2 3 12 4 2 3 11
126: 4 2 3 9 3 2 3 11 5 2 3 12 4 2 3 11 5 2 3 12 3 2 3 11 5
151: 2 3 11 5 2 3 13 4 2 3 12 3 2 3 11 5 2 3 8 3 2 3 10 4 2
176: 3 11 3 2 3 10 5 2 3 11 4 2 3 10 4 2 3 10 3 2 3 12 5 2 3
201: 11

Length of sentence = 1203

The length of word 1000 [in] is 2
Length of sentence = 6249

The length of word 10000 [in] is 2
Length of sentence = 64097

The length of word 100000 [one] is 3
Length of sentence = 659455

The length of word 1000000 [the] is 3
Length of sentence = 7113560

The length of word 10000000 [thousand] is 8
Length of sentence = 70995729
</pre>


=={{header|REXX}}==
=={{header|REXX}}==

Revision as of 14:04, 12 September 2017

Four is the number of letters in the ... is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

The     Four is ...     sequence is based on the counting of the number of letters in the words of the (never─ending) sentence:

  Four is the number of letters in the first word of this sentence, two in the second,
  three in the third, six in the fourth, two in the fifth, seven in the sixth, ··· 


Letters   are defined as the upper- and lowercase letters in the Latin alphabet   (A──►Z   and   a──►z).

Commas are not counted,   nor are hyphens (dashes or minus signs) for such numbers as   twenty─three   (which has   11   letters).

Twenty─three   is considered one word   (which is hyphenated).


Furthermore, the American version of numbers will be used here in this task   (as opposed to the British).

2,000,000,000   is two billion,   not   two milliard.


Task

Write a driver (invoking routine) and a function (subroutine/routine···) that returns the sequence (for any positive integer) of the number of letters in the first   N   words in the never─ending sentence.

For instance, the portion of the never─ending sentence shown above (2nd sentence of this task), the sequence would be:

  4  2  3  6  2  7


Only construct as much as is needed for the never─ending sentence.


After the sequence is displayed, also show the total number of characters   (including blanks, commas, and punctuation)   of the sentence that was constructed.


Also, write a driver (invoking routine) to show the number of letters in the   Nth   word,   as well as   the   Nth   word itself.


Show all output here.


Test cases
 Display the first  201  numbers in the sequence   (and the total number of characters in the sentence).
 Display the number of letters  (and the word itself)  of the       1,000th  word.
 Display the number of letters  (and the word itself)  of the      10,000th  word.
 Display the number of letters  (and the word itself)  of the     100,000th  word.
 Display the number of letters  (and the word itself)  of the   1,000,000th  word.
 Display the number of letters  (and the word itself)  of the  10,000,000th  word  (optional).


Related tasks



Kotlin

This pulls in (slightly adjusted) code from related tasks to convert numbers to text or ordinals.

Although it's not actually part of the current task, my sentence lengths for n >= 1000 (but not for n == 201) are somewhat lower than those of the REXX entry. I have not been able to figure out why. <lang scala>// version 1.1.4-3

val names = mapOf(

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

) val bigNames = mapOf(

   1_000L to "thousand",
   1_000_000L to "million",
   1_000_000_000L to "billion",
   1_000_000_000_000L to "trillion",
   1_000_000_000_000_000L to "quadrillion",
   1_000_000_000_000_000_000L to "quintillion"

)

val irregOrdinals = mapOf(

   "one" to "first",
   "two" to "second",
   "three" to "third",
   "five" to "fifth",
   "eight" to "eighth",
   "nine" to "ninth",
   "twelve" to "twelfth"

)

fun String.toOrdinal(): String {

   if (this == "zero") return "zeroth"  // or alternatively 'zeroeth'
   val splits = this.split(' ', '-')
   var last = splits[splits.lastIndex]
   return if (irregOrdinals.containsKey(last)) this.dropLast(last.length) + irregOrdinals[last]!!
          else if (last.endsWith("y")) this.dropLast(1) + "ieth"
          else this + "th"

}

fun numToText(n: Long, uk: Boolean = false): String {

   if (n == 0L) return "zero"
   val neg = n < 0L
   val maxNeg = n == Long.MIN_VALUE
   var nn = if (maxNeg) -(n + 1) else if (neg) -n else n
   val digits3 = IntArray(7)
   for (i in 0..6) {  // split number into groups of 3 digits from the right
       digits3[i] = (nn % 1000).toInt()
       nn /= 1000
   }
   fun threeDigitsToText(number: Int) : String {
       val sb = StringBuilder()
       if (number == 0) return ""
       val hundreds = number / 100
       val remainder = number % 100
       if (hundreds > 0) {
           sb.append(names[hundreds], " hundred")
           if (remainder > 0) sb.append(if (uk) " and " else " ")
       }
       if (remainder > 0) {
           val tens = remainder / 10
           val units = remainder % 10
           if (tens > 1) {
               sb.append(names[tens * 10])
               if (units > 0) sb.append("-", names[units])
           }
           else sb.append(names[remainder])
       }
       return sb.toString()
   }
   val strings = Array<String>(7) { threeDigitsToText(digits3[it]) }
   var text = strings[0]
   var andNeeded = uk && digits3[0] in 1..99
   var big = 1000L
   for (i in 1..6) {
       if (digits3[i] > 0) {
           var text2 = strings[i] + " " + bigNames[big]
           if (text.length > 0) {
               text2 += if (andNeeded) " and " else " "  // no commas inserted in this version
               andNeeded = false
           }
           else andNeeded = uk && digits3[i] in 1..99
           text = text2 + text
       }
       big *= 1000
   }
   if (maxNeg) text = text.dropLast(5) + "eight"
   if (neg) text = "minus " + text
   return text

}

val opening = "Four is the number of letters in the first word of this sentence,".split(' ')

val String.adjustedLength get() = this.replace(",", "").replace("-", "").length // no ',' or '-'

fun getWords(n: Int): List<String> {

   val words = mutableListOf<String>()
   words.addAll(opening)
   if (n > opening.size) {
       var k = 2
       while (true) {
           val len = words[k - 1].adjustedLength
           val text = numToText(len.toLong())
           val splits = text.split(' ')
           words.addAll(splits)
           if (words.size >= n) break
           words.add("in")
           if (words.size == n) break
           words.add("the")
           if (words.size == n) break
           val text2 = numToText(k.toLong()).toOrdinal() + ","  // add trailing comma
           val splits2 = text2.split(' ')
           words.addAll(splits2)
           if (words.size >= n) break
           k++
       }
   }
   return words.take(n)

}

fun getLengths(n: Int): Pair<List<Int>, Int> {

   val words = getWords(n)
   val lengths = words.map { it.adjustedLength }
   val sentenceLength = words.sumBy { it.length } + n - 1  // includes hyphens, commas & spaces
   return Pair(lengths, sentenceLength)

}

fun getLastWord(n: Int): Triple<String, Int, Int> {

   val words = getWords(n)
   val lastWord = words.last()
   val lastWordLength = lastWord.adjustedLength
   val sentenceLength = words.sumBy { it.length } + n - 1  // includes hyphens, commas & spaces
   return Triple(lastWord, lastWordLength, sentenceLength)

}

fun main(args: Array<String>) {

   var n = 201
   println("The lengths of the first $n words are:\n")
   val (list, sentenceLength) = getLengths(n)
   for (i in 0 until n) {
       if (i % 25 == 0) {
           if (i > 0) println()
           print("${"%3d".format(i + 1)}: ")
       }
       print("%3d".format(list[i]))
   }
   println("\n\nLength of sentence = $sentenceLength\n")
   n = 1_000
   do {
       var (word, wLen, sLen) = getLastWord(n)
       if (word.endsWith(",")) word = word.dropLast(1)  // strip off any trailing comma
       println("The length of word $n [$word] is $wLen")
       println("Length of sentence = $sLen\n")
       n *= 10
   }
   while (n <= 10_000_000)

}</lang>

Output:
The lengths of the first 201 words are:

  1:   4  2  3  6  2  7  2  3  5  4  2  4  8  3  2  3  6  5  2  3  5  3  2  3  6
 26:   3  2  3  5  5  2  3  5  3  2  3  7  5  2  3  6  4  2  3  5  4  2  3  5  3
 51:   2  3  8  4  2  3  7  5  2  3 10  5  2  3 10  3  2  3  9  5  2  3  9  3  2
 76:   3 11  4  2  3 10  3  2  3 10  5  2  3  9  4  2  3 11  5  2  3 12  3  2  3
101:  11  5  2  3 12  3  2  3 11  5  2  3 11  3  2  3 13  5  2  3 12  4  2  3 11
126:   4  2  3  9  3  2  3 11  5  2  3 12  4  2  3 11  5  2  3 12  3  2  3 11  5
151:   2  3 11  5  2  3 13  4  2  3 12  3  2  3 11  5  2  3  8  3  2  3 10  4  2
176:   3 11  3  2  3 10  5  2  3 11  4  2  3 10  4  2  3 10  3  2  3 12  5  2  3
201:  11

Length of sentence = 1203

The length of word 1000 [in] is 2
Length of sentence = 6249

The length of word 10000 [in] is 2
Length of sentence = 64097

The length of word 100000 [one] is 3
Length of sentence = 659455

The length of word 1000000 [the] is 3
Length of sentence = 7113560

The length of word 10000000 [thousand] is 8
Length of sentence = 70995729

REXX

<lang rexx>/*REXX pgm finds/shows the number of letters in the Nth word in a constructed sentence*/ @= 'Four is the number of letters in the first word of this sentence,' /*···*/

                                                /* [↑]   the start of a long sentence. */

parse arg N M /*obtain optional argument from the CL.*/ if N= | N="," then N= 201 /*Not specified? Then use the default.*/ if M= | M="," then M=1000 10000 100000 1000000 /* " " " " " " */ @abcU= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' /*define the uppercase Latin alphabet. */ !.=.; #.=.; q=1; w=length(N) /* [↓] define some helpful low values.*/ call tell N if N<0 then say y ' is the length of word ' a " ["word(@, a)"]" say /* [↑] N negative? Just show 1 number*/ say 'length of sentence= ' length(@) /*display the length of the @ sentence.*/

if M\== then do k=1 for words(M) while M\=0 /*maybe handle counts (if specified). */

               x=word(M, k)                     /*obtain the  Kth  word of the M list. */
               call tell  -x                    /*invoke subroutine (with negative arg)*/
               say
               say y     ' is the length of word '      x       "  ["word(@, x)"]"
               say 'length of sentence= '  length(@)    /*display length of @ sentence.*/
               end   /*k*/

exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ wordLen: arg ?; return length(?) - length( space( translate(?, , @abcU), 0) ) /*──────────────────────────────────────────────────────────────────────────────────────*/ tell: parse arg z,,$; idx=1; a=abs(z); group=25 /*show 25 numbers per line.*/

                                                /*Q is the last number spelt by $SPELL#*/
       do j=1  for a                            /*traipse through all the numbers to N.*/
         do 2                                   /*perform loop twice  (well ··· maybe).*/
         y=wordLen( word(@, j) )                /*get the  Jth  word from the sentence.*/
         if y\==0  then leave                   /*Is the word spelt?   Then we're done.*/
         q=q + 1                                /*bump the on─going (moving) # counter.*/
         if #.q==.  then #.q=$spell#(q 'Q ORD') /*need to spell A as an ordinal number?*/
              _=wordLen( word(@, q) )           /*use the length of the ordinal number.*/
         if !._==.  then !._=$spell#(_ 'Q')     /*Not spelled?   Then go and spell it. */
         @=@  !._   'in the'    #.q","          /*append words to never─ending sentence*/
         end   /*2*/                            /* [↑]   Q ≡ Quiet      ORD ≡ ORDinal  */
       $=$ || right(y, 3)                       /* [↓]  append a justified # to a line.*/
       if j//group==0 & z>0  then do; say right(idx, w)'►'$;   idx=idx+group;   $=;   end
       end   /*j*/                              /* [↑]  show line if there's enough #s.*/
     if $\== & z>0 then say right(idx, w)'►'$ /*display if there are residual numbers*/
     return</lang>

The   $SPELL#.REX   routine can be found here   ───►   $SPELL#.REX.

output:
  1►  4  2  3  6  2  7  2  3  5  4  2  4  8  3  2  3  6  5  2  3  5  3  2  3  6
 26►  3  2  3  5  5  2  3  5  3  2  3  7  5  2  3  6  4  2  3  5  4  2  3  5  3
 51►  2  3  8  4  2  3  7  5  2  3 10  5  2  3 10  3  2  3  9  5  2  3  9  3  2
 76►  3 11  4  2  3 10  3  2  3 10  5  2  3  9  4  2  3 11  5  2  3 12  3  2  3
101► 11  5  2  3 12  3  2  3 11  5  2  3 11  3  2  3 13  5  2  3 12  4  2  3 11
126►  4  2  3  9  3  2  3 11  5  2  3 12  4  2  3 11  5  2  3 12  3  2  3 11  5
151►  2  3 11  5  2  3 13  4  2  3 12  3  2  3 11  5  2  3  8  3  2  3 10  4  2
176►  3 11  3  2  3 10  5  2  3 11  4  2  3 10  4  2  3 10  3  2  3 12  5  2  3
201► 11

length of sentence=  1203

2  is the length of word  1000   [in]
length of sentence=  6279

2  is the length of word  10000   [in]
length of sentence=  64140

3  is the length of word  100000   [one]
length of sentence=  659474

3  is the length of word  1000000   [the]
length of sentence=  7113621