Four is the number of letters in the ...
You are encouraged to solve this task according to the task description, using any language you may know.
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, ···
- Definitions and directives
-
- English is to be used in spelling numbers.
- 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).
- twenty─three has eleven letters.
- twenty─three is considered one word (which is hyphenated).
- no and words are to be used when spelling a (English) word for a number.
- The American version of numbers will be used here in this task (as opposed to the British version).
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.
- Write a driver (invoking routine) to show the number of letters in the Nth word, as well as showing the Nth word itself.
- After each test case, show the total number of characters (including blanks, commas, and punctuation) of the sentence that was constructed.
- 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
- Also see
-
- See the OEIS sequence A72425 "Four is the number of letters...".
- See the OEIS sequence A72424 "Five's the number of letters..."
C
<lang c>#include <ctype.h>
- include <locale.h>
- include <stdbool.h>
- include <stdio.h>
- include <stdint.h>
- include <glib.h>
typedef uint64_t integer;
typedef struct number_names_tag {
const char* cardinal; const char* ordinal;
} number_names;
const number_names small[] = {
{ "zero", "zeroth" }, { "one", "first" }, { "two", "second" }, { "three", "third" }, { "four", "fourth" }, { "five", "fifth" }, { "six", "sixth" }, { "seven", "seventh" }, { "eight", "eighth" }, { "nine", "ninth" }, { "ten", "tenth" }, { "eleven", "eleventh" }, { "twelve", "twelfth" }, { "thirteen", "thirteenth" }, { "fourteen", "fourteenth" }, { "fifteen", "fifteenth" }, { "sixteen", "sixteenth" }, { "seventeen", "seventeenth" }, { "eighteen", "eighteenth" }, { "nineteen", "nineteenth" }
};
const number_names tens[] = {
{ "twenty", "twentieth" }, { "thirty", "thirtieth" }, { "forty", "fortieth" }, { "fifty", "fiftieth" }, { "sixty", "sixtieth" }, { "seventy", "seventieth" }, { "eighty", "eightieth" }, { "ninety", "ninetieth" }
};
typedef struct named_number_tag {
const char* cardinal; const char* ordinal; integer number;
} named_number;
const named_number named_numbers[] = {
{ "hundred", "hundredth", 100 }, { "thousand", "thousandth", 1000 }, { "million", "millionth", 1000000 }, { "billion", "biliionth", 1000000000 }, { "trillion", "trillionth", 1000000000000 }, { "quadrillion", "quadrillionth", 1000000000000000ULL }, { "quintillion", "quintillionth", 1000000000000000000ULL }
};
const char* get_small_name(const number_names* n, bool ordinal) {
return ordinal ? n->ordinal : n->cardinal;
}
const char* get_big_name(const named_number* n, bool ordinal) {
return ordinal ? n->ordinal : n->cardinal;
}
const named_number* get_named_number(integer n) {
const size_t names_len = sizeof(named_numbers)/sizeof(named_numbers[0]); for (size_t i = 0; i + 1 < names_len; ++i) { if (n < named_numbers[i + 1].number) return &named_numbers[i]; } return &named_numbers[names_len - 1];
}
typedef struct word_tag {
size_t offset; size_t length;
} word_t;
typedef struct word_list_tag {
GArray* words; GString* str;
} word_list;
void word_list_create(word_list* words) {
words->words = g_array_new(FALSE, FALSE, sizeof(word_t)); words->str = g_string_new(NULL);
}
void word_list_destroy(word_list* words) {
g_string_free(words->str, TRUE); g_array_free(words->words, TRUE);
}
void word_list_clear(word_list* words) {
g_string_truncate(words->str, 0); g_array_set_size(words->words, 0);
}
void word_list_append(word_list* words, const char* str) {
size_t offset = words->str->len; size_t len = strlen(str); g_string_append_len(words->str, str, len); word_t word; word.offset = offset; word.length = len; g_array_append_val(words->words, word);
}
word_t* word_list_get(word_list* words, size_t index) {
return &g_array_index(words->words, word_t, index);
}
void word_list_extend(word_list* words, const char* str) {
word_t* word = word_list_get(words, words->words->len - 1); size_t len = strlen(str); word->length += len; g_string_append_len(words->str, str, len);
}
size_t append_number_name(word_list* words, integer n, bool ordinal) {
size_t count = 0; if (n < 20) { word_list_append(words, get_small_name(&small[n], ordinal)); count = 1; } else if (n < 100) { if (n % 10 == 0) { word_list_append(words, get_small_name(&tens[n/10 - 2], ordinal)); } else { word_list_append(words, get_small_name(&tens[n/10 - 2], false)); word_list_extend(words, "-"); word_list_extend(words, get_small_name(&small[n % 10], ordinal)); } count = 1; } else { const named_number* num = get_named_number(n); integer p = num->number; count += append_number_name(words, n/p, false); if (n % p == 0) { word_list_append(words, get_big_name(num, ordinal)); ++count; } else { word_list_append(words, get_big_name(num, false)); ++count; count += append_number_name(words, n % p, ordinal); } } return count;
}
size_t count_letters(word_list* words, size_t index) {
const word_t* word = word_list_get(words, index); size_t letters = 0; const char* s = words->str->str + word->offset; for (size_t i = 0, n = word->length; i < n; ++i) { if (isalpha((unsigned char)s[i])) ++letters; } return letters;
}
void sentence(word_list* result, size_t count) {
static const char* words[] = { "Four", "is", "the", "number", "of", "letters", "in", "the", "first", "word", "of", "this", "sentence," }; word_list_clear(result); size_t n = sizeof(words)/sizeof(words[0]); for (size_t i = 0; i < n; ++i) word_list_append(result, words[i]); for (size_t i = 1; count > n; ++i) { n += append_number_name(result, count_letters(result, i), false); word_list_append(result, "in"); word_list_append(result, "the"); n += 2; n += append_number_name(result, i + 1, true); // Append a comma to the final word word_list_extend(result, ","); }
}
size_t sentence_length(const word_list* words) {
size_t n = words->words->len; if (n == 0) return 0; return words->str->len + n - 1;
}
int main() {
setlocale(LC_ALL, ""); size_t n = 201; word_list result = { 0 }; word_list_create(&result); sentence(&result, n); printf("Number of letters in first %'lu words in the sequence:\n", n); for (size_t i = 0; i < n; ++i) { if (i != 0) printf("%c", i % 25 == 0 ? '\n' : ' '); printf("%'2lu", count_letters(&result, i)); } printf("\nSentence length: %'lu\n", sentence_length(&result)); for (n = 1000; n <= 10000000; n *= 10) { sentence(&result, n); const word_t* word = word_list_get(&result, n - 1); const char* s = result.str->str + word->offset; printf("The %'luth word is '%.*s' and has %lu letters. ", n, (int)word->length, s, count_letters(&result, n - 1)); printf("Sentence length: %'lu\n" , sentence_length(&result)); } word_list_destroy(&result); return 0;
}</lang>
- Output:
Number of letters in first 201 words in the sequence: 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 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 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 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 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 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 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 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 11 Sentence length: 1,203 The 1,000th word is 'in' and has 2 letters. Sentence length: 6,279 The 10,000th word is 'in' and has 2 letters. Sentence length: 64,140 The 100,000th word is 'one' and has 3 letters. Sentence length: 659,474 The 1,000,000th word is 'the' and has 3 letters. Sentence length: 7,113,621 The 10,000,000th word is 'thousand' and has 8 letters. Sentence length: 70,995,756
C++
<lang cpp>#include <cctype>
- include <cstdint>
- include <iomanip>
- include <iostream>
- include <string>
- include <vector>
struct number_names {
const char* cardinal; const char* ordinal;
};
const number_names small[] = {
{ "zero", "zeroth" }, { "one", "first" }, { "two", "second" }, { "three", "third" }, { "four", "fourth" }, { "five", "fifth" }, { "six", "sixth" }, { "seven", "seventh" }, { "eight", "eighth" }, { "nine", "ninth" }, { "ten", "tenth" }, { "eleven", "eleventh" }, { "twelve", "twelfth" }, { "thirteen", "thirteenth" }, { "fourteen", "fourteenth" }, { "fifteen", "fifteenth" }, { "sixteen", "sixteenth" }, { "seventeen", "seventeenth" }, { "eighteen", "eighteenth" }, { "nineteen", "nineteenth" }
};
const number_names tens[] = {
{ "twenty", "twentieth" }, { "thirty", "thirtieth" }, { "forty", "fortieth" }, { "fifty", "fiftieth" }, { "sixty", "sixtieth" }, { "seventy", "seventieth" }, { "eighty", "eightieth" }, { "ninety", "ninetieth" }
};
struct named_number {
const char* cardinal; const char* ordinal; uint64_t number;
};
const named_number named_numbers[] = {
{ "hundred", "hundredth", 100 }, { "thousand", "thousandth", 1000 }, { "million", "millionth", 1000000 }, { "billion", "biliionth", 1000000000 }, { "trillion", "trillionth", 1000000000000 }, { "quadrillion", "quadrillionth", 1000000000000000ULL }, { "quintillion", "quintillionth", 1000000000000000000ULL }
};
const char* get_name(const number_names& n, bool ordinal) {
return ordinal ? n.ordinal : n.cardinal;
}
const char* get_name(const named_number& n, bool ordinal) {
return ordinal ? n.ordinal : n.cardinal;
}
const named_number& get_named_number(uint64_t n) {
constexpr size_t names_len = std::size(named_numbers); for (size_t i = 0; i + 1 < names_len; ++i) { if (n < named_numbers[i + 1].number) return named_numbers[i]; } return named_numbers[names_len - 1];
}
size_t append_number_name(std::vector<std::string>& result, uint64_t n, bool ordinal) {
size_t count = 0; if (n < 20) { result.push_back(get_name(small[n], ordinal)); count = 1; } else if (n < 100) { if (n % 10 == 0) { result.push_back(get_name(tens[n/10 - 2], ordinal)); } else { std::string name(get_name(tens[n/10 - 2], false)); name += "-"; name += get_name(small[n % 10], ordinal); result.push_back(name); } count = 1; } else { const named_number& num = get_named_number(n); uint64_t p = num.number; count += append_number_name(result, n/p, false); if (n % p == 0) { result.push_back(get_name(num, ordinal)); ++count; } else { result.push_back(get_name(num, false)); ++count; count += append_number_name(result, n % p, ordinal); } } return count;
}
size_t count_letters(const std::string& str) {
size_t letters = 0; for (size_t i = 0, n = str.size(); i < n; ++i) { if (isalpha(static_cast<unsigned char>(str[i]))) ++letters; } return letters;
}
std::vector<std::string> sentence(size_t count) {
static const char* words[] = { "Four", "is", "the", "number", "of", "letters", "in", "the", "first", "word", "of", "this", "sentence," }; std::vector<std::string> result; result.reserve(count + 10); size_t n = std::size(words); for (size_t i = 0; i < n && i < count; ++i) { result.push_back(words[i]); } for (size_t i = 1; count > n; ++i) { n += append_number_name(result, count_letters(result[i]), false); result.push_back("in"); result.push_back("the"); n += 2; n += append_number_name(result, i + 1, true); result.back() += ','; } return result;
}
size_t sentence_length(const std::vector<std::string>& words) {
size_t n = words.size(); if (n == 0) return 0; size_t length = n - 1; for (size_t i = 0; i < n; ++i) length += words[i].size(); return length;
}
int main() {
std::cout.imbue(std::locale("")); size_t n = 201; auto result = sentence(n); std::cout << "Number of letters in first " << n << " words in the sequence:\n"; for (size_t i = 0; i < n; ++i) { if (i != 0) std::cout << (i % 25 == 0 ? '\n' : ' '); std::cout << std::setw(2) << count_letters(result[i]); } std::cout << '\n'; std::cout << "Sentence length: " << sentence_length(result) << '\n'; for (n = 1000; n <= 10000000; n *= 10) { result = sentence(n); const std::string& word = result[n - 1]; std::cout << "The " << n << "th word is '" << word << "' and has " << count_letters(word) << " letters. "; std::cout << "Sentence length: " << sentence_length(result) << '\n'; } return 0;
}</lang>
- Output:
Number of letters in first 201 words in the sequence: 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 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 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 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 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 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 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 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 11 Sentence length: 1,203 The 1,000th word is 'in' and has 2 letters. Sentence length: 6,279 The 10,000th word is 'in' and has 2 letters. Sentence length: 64,140 The 100,000th word is 'one' and has 3 letters. Sentence length: 659,474 The 1,000,000th word is 'the' and has 3 letters. Sentence length: 7,113,621 The 10,000,000th word is 'thousand' and has 8 letters. Sentence length: 70,995,756
Go
This is a naive non-optimized implementation
that stores each word of the sentence so far.
It uses the
sayOrdinal
and say
functions from the
Spelling of ordinal numbers task
(omitted from this listing).
<lang Go>package main
import ( "fmt" "strings" "unicode" )
func main() { f := NewFourIsSeq() fmt.Print("The lengths of the first 201 words are:") for i := 1; i <= 201; i++ { if i%25 == 1 { fmt.Printf("\n%3d: ", i) } _, n := f.WordLen(i) fmt.Printf(" %2d", n) } fmt.Println() fmt.Println("Length of sentence so far:", f.TotalLength()) /* For debugging: log.Println("sentence:", strings.Join(f.words, " ")) for i, w := range f.words { log.Printf("%3d: %2d %q\n", i, countLetters(w), w) } log.Println(f.WordLen(2202)) log.Println("len(f.words):", len(f.words)) log.Println("sentence:", strings.Join(f.words, " ")) */ for i := 1000; i <= 1e7; i *= 10 { w, n := f.WordLen(i) fmt.Printf("Word %8d is %q, with %d letters.", i, w, n) fmt.Println(" Length of sentence so far:", f.TotalLength()) } }
type FourIsSeq struct { i int // index of last word processed words []string // strings.Join(words," ") gives the sentence so far }
func NewFourIsSeq() *FourIsSeq { return &FourIsSeq{ //words: strings.Fields("Four is the number of letters in the first word of this sentence,"), words: []string{ "Four", "is", "the", "number", "of", "letters", "in", "the", "first", "word", "of", "this", "sentence,", }, } }
// WordLen returns the w'th word and its length (only counting letters). func (f *FourIsSeq) WordLen(w int) (string, int) { for len(f.words) < w { f.i++ n := countLetters(f.words[f.i]) ns := say(int64(n)) os := sayOrdinal(int64(f.i+1)) + "," // append something like: "two in the second," f.words = append(f.words, strings.Fields(ns)...) f.words = append(f.words, "in", "the") f.words = append(f.words, strings.Fields(os)...) } word := f.words[w-1] return word, countLetters(word) }
// TotalLength returns the total number of characters (including blanks, // commas, and punctuation) of the sentence so far constructed. func (f FourIsSeq) TotalLength() int { cnt := 0 for _, w := range f.words { cnt += len(w) + 1 } return cnt - 1 }
func countLetters(s string) int { cnt := 0 for _, r := range s { if unicode.IsLetter(r) { cnt++ } } return cnt }
// ... // the contents of // https://rosettacode.org/wiki/Spelling_of_ordinal_numbers#Go // omitted from this listing // ... </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 so far: 1203 Word 1000 is "in", with 2 letters. Length of sentence so far: 6279 Word 10000 is "in", with 2 letters. Length of sentence so far: 64140 Word 100000 is "one", with 3 letters. Length of sentence so far: 659474 Word 1000000 is "the", with 3 letters. Length of sentence so far: 7113621 Word 10000000 is "thousand", with 8 letters. Length of sentence so far: 70995756
Java
Take care with the requirements. As noted, numberToString(23) = twenty-three. Therefore numberToString(723423) = seven hundred twenty-three thousand four hundred twenty-three (note the two "-").
The discussion was helpful by providing the first 2202 words of the sentence.
<lang java>
import java.util.HashMap;
import java.util.Map;
public class FourIsTheNumberOfLetters {
public static void main(String[] args) { String [] words = neverEndingSentence(201); System.out.printf("Display the first 201 numbers in the sequence:%n%3d: ", 1); for ( int i = 0 ; i < words.length ; i++ ) { System.out.printf("%2d ", numberOfLetters(words[i])); if ( (i+1) % 25 == 0 ) { System.out.printf("%n%3d: ", i+2); } } System.out.printf("%nTotal number of characters in the sentence is %d%n", characterCount(words)); for ( int i = 3 ; i <= 7 ; i++ ) { int index = (int) Math.pow(10, i); words = neverEndingSentence(index); String last = words[words.length-1].replace(",", ""); System.out.printf("Number of letters of the %s word is %d. The word is \"%s\". The sentence length is %,d characters.%n", toOrdinal(index), numberOfLetters(last), last, characterCount(words)); } } @SuppressWarnings("unused") private static void displaySentence(String[] words, int lineLength) { int currentLength = 0; for ( String word : words ) { if ( word.length() + currentLength > lineLength ) { String first = word.substring(0, lineLength-currentLength); String second = word.substring(lineLength-currentLength); System.out.println(first); System.out.print(second); currentLength = second.length(); } else { System.out.print(word); currentLength += word.length(); } if ( currentLength == lineLength ) { System.out.println(); currentLength = 0; } System.out.print(" "); currentLength++; if ( currentLength == lineLength ) { System.out.println(); currentLength = 0; } } System.out.println(); } private static int numberOfLetters(String word) { return word.replace(",","").replace("-","").length(); } private static long characterCount(String[] words) { int characterCount = 0; for ( int i = 0 ; i < words.length ; i++ ) { characterCount += words[i].length() + 1; } // Extra space counted in last loop iteration characterCount--; return characterCount; } private static String[] startSentence = new String[] {"Four", "is", "the", "number", "of", "letters", "in", "the", "first", "word", "of", "this", "sentence,"}; private static String[] neverEndingSentence(int wordCount) { String[] words = new String[wordCount]; int index; for ( index = 0 ; index < startSentence.length && index < wordCount ; index++ ) { words[index] = startSentence[index]; } int sentencePosition = 1; while ( index < wordCount ) { // X in the Y // X sentencePosition++; String word = words[sentencePosition-1]; for ( String wordLoop : numToString(numberOfLetters(word)).split(" ") ) { words[index] = wordLoop; index++; if ( index == wordCount ) { break; } } // in words[index] = "in"; index++; if ( index == wordCount ) { break; } // the words[index] = "the"; index++; if ( index == wordCount ) { break; } // Y for ( String wordLoop : (toOrdinal(sentencePosition) + ",").split(" ") ) { words[index] = wordLoop; index++; if ( index == wordCount ) { break; } } } return words; } private static final String[] nums = new String[] { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" }; private static final String[] tens = new String[] {"zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
private static final String numToString(long n) { return numToStringHelper(n); } private static final String numToStringHelper(long n) { if ( n < 0 ) { return "negative " + numToStringHelper(-n); } int index = (int) n; if ( n <= 19 ) { return nums[index]; } if ( n <= 99 ) { return tens[index/10] + (n % 10 > 0 ? "-" + numToStringHelper(n % 10) : ""); } String label = null; long factor = 0; if ( n <= 999 ) { label = "hundred"; factor = 100; } else if ( n <= 999999) { label = "thousand"; factor = 1000; } else if ( n <= 999999999) { label = "million"; factor = 1000000; } else if ( n <= 999999999999L) { label = "billion"; factor = 1000000000; } else if ( n <= 999999999999999L) { label = "trillion"; factor = 1000000000000L; } else if ( n <= 999999999999999999L) { label = "quadrillion"; factor = 1000000000000000L; } else { label = "quintillion"; factor = 1000000000000000000L; } return numToStringHelper(n / factor) + " " + label + (n % factor > 0 ? " " + numToStringHelper(n % factor ) : ""); }
private static Map<String,String> ordinalMap = new HashMap<>(); static { ordinalMap.put("one", "first"); ordinalMap.put("two", "second"); ordinalMap.put("three", "third"); ordinalMap.put("five", "fifth"); ordinalMap.put("eight", "eighth"); ordinalMap.put("nine", "ninth"); ordinalMap.put("twelve", "twelfth"); } private static String toOrdinal(long n) { String spelling = numToString(n); String[] split = spelling.split(" "); String last = split[split.length - 1]; String replace = ""; if ( last.contains("-") ) { String[] lastSplit = last.split("-"); String lastWithDash = lastSplit[1]; String lastReplace = ""; if ( ordinalMap.containsKey(lastWithDash) ) { lastReplace = ordinalMap.get(lastWithDash); } else if ( lastWithDash.endsWith("y") ) { lastReplace = lastWithDash.substring(0, lastWithDash.length() - 1) + "ieth"; } else { lastReplace = lastWithDash + "th"; } replace = lastSplit[0] + "-" + lastReplace; } else { if ( ordinalMap.containsKey(last) ) { replace = ordinalMap.get(last); } else if ( last.endsWith("y") ) { replace = last.substring(0, last.length() - 1) + "ieth"; } else { replace = last + "th"; } } split[split.length - 1] = replace; return String.join(" ", split); }
} </lang>
- Output:
Display the first 201 numbers in the sequence: 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 Total number of characters in the sentence is 1203 Number of letters of the one thousandth word is 2. The word is "in". The sentence length is 6,249 characters. Number of letters of the ten thousandth word is 2. The word is "in". The sentence length is 64,097 characters. Number of letters of the one hundred thousandth word is 3. The word is "one". The sentence length is 659,455 characters. Number of letters of the one millionth word is 3. The word is "the". The sentence length is 7,113,560 characters. Number of letters of the ten millionth word is 8. The word is "thousand". The sentence length is 70,995,729 characters.
Julia
The functions num2text and numtext2ordinal are from the "Spelling of ordinal numbers" and "Number names" tasks, updated for Julia 1.0 and to remove the "and" words.<lang julia>using DataStructures # for deque
const seed = "Four is the number of letters in the first word of this sentence, " const (word2, word3) = ("in", "the")
lettercount(w) = length(w) - length(collect(eachmatch(r"-", w))) splits(txt) = [x.match for x in eachmatch(r"[\w\-]+", txt)] todq(sentence) = (d = Deque{String}(); map(x->push!(d, x), splits(sentence)[2:end]); d)
struct CountLetters
seedsentence::String words::Deque{String} commasafter::Vector{Int} CountLetters(s) = new(s, todq(s), [13]) CountLetters() = CountLetters(seed)
end
function Base.iterate(iter::CountLetters, state = (1, 5, ""))
if length(iter.words) < 1 return nothing end returnword = popfirst!(iter.words) nextwordindex = state[1] + 1 wordlen = lettercount(returnword) wordvec = vcat(num2text(wordlen), word2, word3, splits(numtext2ordinal(num2text(nextwordindex)))) map(x -> push!(iter.words, x), wordvec) push!(iter.commasafter, length(iter.words)) added = length(returnword) + (nextwordindex in iter.commasafter ? 2 : 1) (wordlen, (nextwordindex, state[2] + added, returnword))
end
Base.eltype(iter::CountLetters) = Int
function firstN(n = 201)
countlet = CountLetters() print("It is interesting how identical lengths align with 20 columns.\n 1: 4") iter_result = iterate(countlet) itercount = 2 while iter_result != nothing (wlen, state) = iter_result print(lpad(string(wlen), 4)) if itercount % 20 == 0 print("\n", lpad(itercount+1, 4), ":") elseif itercount >= n break end iter_result = iterate(countlet, state) itercount += 1 end println()
end
function sumwords(iterations)
countlet = CountLetters() iter_result = iterate(countlet) itercount = 2 while iter_result != nothing (wlen, state) = iter_result if itercount == iterations return state end iter_result = iterate(countlet, state) itercount += 1 end throw("Iteration failed on \"Four is the number\" task.")
end
firstN()
for n in [2202, 1000, 10000, 100000, 1000000, 10000000]
(itercount, totalletters, lastword) = sumwords(n) println("$n words -> $itercount iterations, $totalletters letters total, ", "last word \"$lastword\" with $(length(lastword)) letters.")
end</lang>
- Output:
It is interesting how identical lengths align with 20 columns.
1: 4 2 3 6 2 7 2 3 5 4 2 4 8 3 2 3 6 5 2 3 21: 5 3 2 3 6 3 2 3 5 5 2 3 5 3 2 3 7 5 2 3 41: 6 4 2 3 5 4 2 3 5 3 2 3 8 4 2 3 7 5 2 3 61: 10 5 2 3 10 3 2 3 9 5 2 3 9 3 2 3 11 4 2 3 81: 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 121: 12 4 2 3 11 4 2 3 9 3 2 3 11 5 2 3 12 4 2 3 141: 11 5 2 3 12 3 2 3 11 5 2 3 11 5 2 3 13 4 2 3 161: 12 3 2 3 11 5 2 3 8 3 2 3 10 4 2 3 11 3 2 3 181: 10 5 2 3 11 4 2 3 10 4 2 3 10 3 2 3 12 5 2 3 201: 112202 words -> 2202 iterations, 14035 letters total, last word "ninety-ninth" with 12 letters. 1000 words -> 1000 iterations, 6290 letters total, last word "in" with 2 letters. 10000 words -> 10000 iterations, 64320 letters total, last word "in" with 2 letters. 100000 words -> 100000 iterations, 661369 letters total, last word "one" with 3 letters. 1000000 words -> 1000000 iterations, 7127541 letters total, last word "the" with 3 letters. 10000000 words -> 10000000 iterations, 71103026 letters total, last word "thousand" with 8 letters.
Kotlin
This pulls in (slightly adjusted) code from related tasks to convert numbers to text or ordinals. <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(' ', '-') val 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(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.isNotEmpty()) { 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) words.add("in") words.add("the") val text2 = numToText(k.toLong()).toOrdinal() + "," // add trailing comma val splits2 = text2.split(' ') words.addAll(splits2) if (words.size >= n) break k++ } } return words
}
fun getLengths(n: Int): Pair<List<Int>, Int> {
val words = getWords(n) val lengths = words.take(n).map { it.adjustedLength } val sentenceLength = words.sumBy { it.length } + words.size - 1 // includes hyphens, commas & spaces return Pair(lengths, sentenceLength)
}
fun getLastWord(n: Int): Triple<String, Int, Int> {
val words = getWords(n) val nthWord = words[n - 1] val nthWordLength = nthWord.adjustedLength val sentenceLength = words.sumBy { it.length } + words.size - 1 // includes hyphens, commas & spaces return Triple(nthWord, nthWordLength, 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 = 6279 The length of word 10000 [in] is 2 Length of sentence = 64140 The length of word 100000 [one] is 3 Length of sentence = 659474 The length of word 1000000 [the] is 3 Length of sentence = 7113621 The length of word 10000000 [thousand] is 8 Length of sentence = 70995756
Nim
<lang Nim>import strutils, strformat, tables
- Cardinal and ordinal strings.
const
Small = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
Tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
Illions = ["", " thousand", " million", " billion", " trillion", " quadrillion", " quintillion"]
IrregularOrdinals = {"one": "first", "two": "second", "three": "third", "five": "fifth", "eight": "eighth", "nine": "ninth", "twelve": "twelfth"}.toTable()
- ---------------------------------------------------------------------------------------------------
func spellCardinal(n: int64): string =
## Spell an integer as a cardinal.
var n = n
if n < 0: result = "negative " n = -n
if n < 20: result &= Small[n]
elif n < 100: result &= Tens[n div 10] let m = n mod 10 if m != 0: result &= '-' & Small[m]
elif n < 1000: result &= Small[n div 100] & " hundred" let m = n mod 100 if m != 0: result &= ' ' & m.spellCardinal()
else: # Work from right to left. var sx = "" var i = 0 while n > 0: let m = n mod 1000 n = n div 1000 if m != 0: var ix = m.spellCardinal() & Illions[i] if sx.len > 0: ix &= " " & sx sx = ix inc i result &= sx
- ---------------------------------------------------------------------------------------------------
func spellOrdinal(n: int64): string =
## Spell an integer as an ordinal.
result = n.spellCardinal() var parts = result.rsplit({' ', '-'}, maxsplit = 1) let tail = parts[^1] if tail in IrregularOrdinals: result[^tail.len..^1] = IrregularOrdinals[tail] elif tail.endsWith('y'): result[^1..^1]= "ieth" else: result &= "th"
- Sentence building.
type Sentence = seq[string]
- ---------------------------------------------------------------------------------------------------
iterator words(sentence: var Sentence): tuple[idx: int; word: string] =
## Yield the successive words of the sentence with their index.
yield (0, "Four") var idx = 1 var last = 0 while true: yield (idx, sentence[idx]) inc idx if idx == sentence.len: inc last sentence.add([sentence[last].count(Letters).spellCardinal(), "in", "the"]) # For the position, we need to split the ordinal as it may contain spaces. sentence.add(((last + 1).spellOrdinal() & ',').splitWhitespace())
- ---------------------------------------------------------------------------------------------------
iterator letterCounts(sentence: var Sentence): tuple[idx: int; word: string; count: int] =
## Secondary iterator used to yield the number of letters in addition to the index and the word.
for i, word in sentence.words(): yield (i, word, word.count(Letters))
- Drivers.
- Constant to initialize the sentence.
const Init = "Four is the number of letters in the first word of this sentence,".splitWhitespace()
- ---------------------------------------------------------------------------------------------------
proc displayLetterCounts(pos: Positive) =
## Display the number of letters of the word at position "pos".
var sentence = Init echo fmt"Number of letters in first {pos} words in the sequence:" var valcount = 0 # Number of values displayed in the current line. var length = 0
for i, word, letterCount in sentence.letterCounts(): if i == pos: # Terminated. dec length # Adjust space count. echo "" break
if valcount == 0: stdout.write fmt"{i+1:>3}:" stdout.write fmt"{letterCount:>3}" inc valcount inc length, word.len + 1 # +1 for space.
if valcount == 12: # Terminate line. echo "" valcount = 0
echo fmt"Sentence length: {length}"
- ---------------------------------------------------------------------------------------------------
proc displayWord(pos: Positive) =
## Display the word at position "pos".
var sentence = Init let idx = pos - 1 var length = 0 for i, word in sentence.words(): length += word.len + 1 if i == idx: dec length # Adjust space count. let w = word.strip(leading = false, chars = {','}) # Remove trailing ',' if needed. echo fmt"Word {pos} is ""{w}"" with {w.count(Letters)} letters." echo fmt"Length of sequence: {length}" break
- ———————————————————————————————————————————————————————————————————————————————————————————————————
displayLetterCounts(201) for n in [1_000, 10_000, 100_000, 1_000_000, 10_000_000]:
echo "" displayWord(n)</lang>
- Output:
Number of letters in first 201 words in the sequence: 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 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 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 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 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 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 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 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 11 Sentence length: 1203 Word 1000 is "in" with 2 letters. Length of sequence: 6249 Word 10000 is "in" with 2 letters. Length of sequence: 64097 Word 100000 is "one" with 3 letters. Length of sequence: 659455 Word 1000000 is "the" with 3 letters. Length of sequence: 7113560 Word 10000000 is "thousand" with 8 letters. Length of sequence: 70995729
Perl
Uses Lingua::EN::Numbers
module to generate number names. State variable in extend_to routine keeps track of last word tallied.
<lang perl>use feature 'state'; use Lingua::EN::Numbers qw(num2en num2en_ordinal);
my @sentence = split / /, 'Four is the number of letters in the first word of this sentence, ';
sub extend_to {
my($last) = @_; state $index = 1; until ($#sentence > $last) { push @sentence, split ' ', num2en(alpha($sentence[$index])) . ' in the ' . no_c(num2en_ordinal(1+$index)) . ','; $index++; }
}
sub alpha { my($s) = @_; $s =~ s/\W//gi; length $s } sub no_c { my($s) = @_; $s =~ s/\ and|,//g; return $s } sub count { length(join ' ', @sentence[0..-1+$_[0]]) . " characters in the sentence, up to and including this word.\n" }
print "First 201 word lengths in the sequence:\n"; extend_to(201); for (0..200) {
printf "%3d", alpha($sentence[$_]); print "\n" unless ($_+1) % 32;
} print "\n" . count(201) . "\n";
for (1e3, 1e4, 1e5, 1e6, 1e7) {
extend_to($_); print ucfirst(num2en_ordinal($_)) . " word, '$sentence[$_-1]' has " . alpha($sentence[$_-1]) . " characters. \n" . count($_) . "\n";
}</lang>
- Output:
First 201 word lengths in the sequence: 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 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 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 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 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 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 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 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 11 1203 characters in the sentence, up to and including this word. One thousandth word, 'in' has 2 characters. 6249 characters in the sentence, up to and including this word. Ten thousandth word, 'in' has 2 characters. 64097 characters in the sentence, up to and including this word. One hundred thousandth word, 'one' has 3 characters. 659455 characters in the sentence, up to and including this word. One millionth word, 'the' has 3 characters. 7113560 characters in the sentence, up to and including this word. Ten millionth word, 'thousand' has 8 characters. 70995729 characters in the sentence, up to and including this word.
Phix
Note that my version of Number_names includes "and" (and ","), that others do not, hence the kill_and()/grr below and the minor mismatch of sentence lengths. <lang Phix>include demo\rosetta\number_names.exw
-- as per Spelling_of_ordinal_numbers#Phix: constant {irregs,ordinals} = columnize({{"one","first"},
{"two","second"}, {"three","third"}, {"five","fifth"}, {"eight","eighth"}, {"nine","ninth"}, {"twelve","twelfth"}})
function ordinal(string s)
integer i for i=length(s) to 1 by -1 do integer ch = s[i] if ch=' ' or ch='-' then exit end if end for integer k = find(s[i+1..$],irregs) if k then s = s[1..i]&ordinals[k] elsif s[$]='y' then s[$..$] = "ieth" else s &= "th" end if return s
end function --/copy of Spelling_of_ordinal_numers#Phix
function countLetters(string s)
integer res = 0 for i=1 to length(s) do integer ch = s[i] if (ch>='A' and ch<='Z') or (ch>='a' and ch<='z') then res += 1 end if end for return res
end function
sequence words = split("Four is the number of letters in the first word of this sentence,") integer fi = 1
function kill_and(sequence s) --grr...
for i=length(s) to 1 by -1 do if s[i] = "and" then s[i..i] = {} end if end for return s
end function
function WordLen(integer w) -- Returns the w'th word and its length (only counting letters).
while length(words)<w do fi += 1 integer n = countLetters(words[fi]) sequence ns = kill_and(split(spell(n))) sequence os = kill_and(split(ordinal(spell(fi)) & ",")) -- append eg {"two","in","the","second,"} words &= ns&{"in","the"}&os end while string word = words[w] return {word, countLetters(word)}
end function
function TotalLength() -- Returns the total number of characters (including blanks, -- commas, and punctuation) of the sentence so far constructed.
integer res = 0 for i=1 to length(words) do res += length(words[i])+1 end for return res
end function
procedure main() integer i,n string w
printf(1,"The lengths of the first 201 words are:\n") for i=1 to 201 do if mod(i,25)==1 then printf(1,"\n%3d: ", i) end if {?,n} = WordLen(i) printf(1," %2d", n) end for printf(1,"\nLength of sentence so far:%d\n", TotalLength()) for p=3 to 7 do i = power(10,p) {w, n} = WordLen(i) printf(1,"Word %8d is \"%s\", with %d letters.", {i, w, n}) printf(1," Length of sentence so far:%d\n", TotalLength()) end for
end procedure main()</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 so far:1204 Word 1000 is "in", with 2 letters. Length of sentence so far:6280 Word 10000 is "in", with 2 letters. Length of sentence so far:64692 Word 100000 is "one", with 3 letters. Length of sentence so far:671578 Word 1000000 is "the", with 3 letters. Length of sentence so far:7235383 Word 10000000 is "thousand,", with 8 letters. Length of sentence so far:72079160
Python
<lang Python>
- Python implementation of Rosetta Code Task
- http://rosettacode.org/wiki/Four_is_the_number_of_letters_in_the_...
- Uses inflect
- https://pypi.org/project/inflect/
import inflect
def count_letters(word):
""" count letters ignore , or -, or space """ count = 0 for letter in word: if letter != ',' and letter !='-' and letter !=' ': count += 1 return count
def split_with_spaces(sentence):
""" Takes string with partial sentence and returns list of words with spaces included. Leading space is attached to first word. Later spaces attached to prior word. """ sentence_list = [] curr_word = "" for c in sentence: if c == " " and curr_word != "": # append space to end of non-empty words # assumed no more than 1 consecutive space. sentence_list.append(curr_word+" ") curr_word = "" else: curr_word += c # add trailing word that does not end with a space if len(curr_word) > 0: sentence_list.append(curr_word) return sentence_list
def my_num_to_words(p, my_number):
""" Front end to inflect's number_to_words Get's rid of ands and commas in large numbers. """ number_string_list = p.number_to_words(my_number, wantlist=True, andword=) number_string = number_string_list[0] for i in range(1,len(number_string_list)): number_string += " " + number_string_list[i] return number_string
def build_sentence(p, max_words):
""" Builds at most max_words of the task following the pattern: 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, """ # start with first part of sentence up first comma as a list sentence_list = split_with_spaces("Four is the number of letters in the first word of this sentence,") num_words = 13 # which word number we are doing next # two/second is first one in loop word_number = 2 # loop until sentance is at least as long as needs be while num_words < max_words: # Build something like # ,two in the second # get second or whatever we are on ordinal_string = my_num_to_words(p, p.ordinal(word_number)) # get two or whatever the length is of the word_number word word_number_string = my_num_to_words(p, count_letters(sentence_list[word_number - 1])) # sentence addition new_string = " "+word_number_string+" in the "+ordinal_string+","
new_list = split_with_spaces(new_string) sentence_list += new_list
# add new word count num_words += len(new_list) # increment word number word_number += 1 return sentence_list, num_words
def word_and_counts(word_num):
""" Print's lines like this: Word 1000 is "in", with 2 letters. Length of sentence so far: 6279
""" sentence_list, num_words = build_sentence(p, word_num) word_str = sentence_list[word_num - 1].strip(' ,') num_letters = len(word_str) num_characters = 0 for word in sentence_list: num_characters += len(word) print('Word {0:8d} is "{1}", with {2} letters. Length of the sentence so far: {3} '.format(word_num,word_str,num_letters,num_characters))
p = inflect.engine()
sentence_list, num_words = build_sentence(p, 201)
print(" ") print("The lengths of the first 201 words are:") print(" ")
print('{0:3d}: '.format(1),end=)
total_characters = 0
for word_index in range(201):
word_length = count_letters(sentence_list[word_index]) total_characters += len(sentence_list[word_index]) print('{0:2d}'.format(word_length),end=) if (word_index+1) % 20 == 0: # newline every 20 print(" ") print('{0:3d}: '.format(word_index + 2),end=) else: print(" ",end=)
print(" ") print(" ") print("Length of the sentence so far: "+str(total_characters)) print(" ")
"""
Expected output this part:
Word 1000 is "in", with 2 letters. Length of the sentence so far: 6279 Word 10000 is "in", with 2 letters. Length of the sentence so far: 64140 Word 100000 is "one", with 3 letters. Length of the sentence so far: 659474 Word 1000000 is "the", with 3 letters. Length of the sentence so far: 7113621 Word 10000000 is "thousand", with 8 letters. Length of the sentence so far: 70995756
"""
word_and_counts(1000) word_and_counts(10000) word_and_counts(100000) word_and_counts(1000000) word_and_counts(10000000) </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 21: 5 3 2 3 6 3 2 3 5 5 2 3 5 3 2 3 7 5 2 3 41: 6 4 2 3 5 4 2 3 5 3 2 3 8 4 2 3 7 5 2 3 61: 10 5 2 3 10 3 2 3 9 5 2 3 9 3 2 3 11 4 2 3 81: 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 121: 12 4 2 3 11 4 2 3 9 3 2 3 11 5 2 3 12 4 2 3 141: 11 5 2 3 12 3 2 3 11 5 2 3 11 5 2 3 13 4 2 3 161: 12 3 2 3 11 5 2 3 8 3 2 3 10 4 2 3 11 3 2 3 181: 10 5 2 3 11 4 2 3 10 4 2 3 10 3 2 3 12 5 2 3 201: 11 Length of the sentence so far: 1203 Word 1000 is "in", with 2 letters. Length of the sentence so far: 6279 Word 10000 is "in", with 2 letters. Length of the sentence so far: 64140 Word 100000 is "one", with 3 letters. Length of the sentence so far: 659474 Word 1000000 is "the", with 3 letters. Length of the sentence so far: 7113621 Word 10000000 is "thousand", with 8 letters. Length of the sentence so far: 70995756
Raku
(formerly Perl 6)
Uses the Lingua::EN::Numbers module to generate both cardinal and ordinal numbers. This module places commas in number words between 3-orders-of-magnitude clusters. E.G. 12345678.&ordinal
becomes: twelve million, three hundred forty-five thousand, six hundred seventy-eighth. Uses a custom 'no-commas' routine to filter them out for accurate character counts. Generates the 'sentence' lazily so only the words needed are ever calculated and reified.
<lang perl6>use Lingua::EN::Numbers; no-commas(True);
my $index = 1; my @sentence = flat 'Four is the number of letters in the first word of this sentence, '.words,
{ @sentence[$index++].&alpha.&cardinal, 'in', 'the', |($index.&ordinal ~ ',').words } ... * ;
sub alpha ( $str ) { $str.subst(/\W/, , :g).chars } sub count ( $index ) { @sentence[^$index].join(' ').chars ~ " characters in the sentence, up to and including this word.\n" }
say 'First 201 word lengths in the sequence:'; put ' ', map { @sentence[$_].&alpha.fmt("%2d") ~ (((1+$_) %% 25) ?? "\n" !! ) }, ^201; say 201.&count;
for 1e3, 1e4, 1e5, 1e6, 1e7 {
say "{.&ordinal.tc} word, '{@sentence[$_ - 1]}', has {@sentence[$_ - 1].&alpha} characters. ", .&count
}</lang>
- Output:
First 201 word lengths in the sequence: 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 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 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 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 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 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 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 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 11 1203 characters in the sentence, up to and including this word. One thousandth word, 'in', has 2 characters. 6249 characters in the sentence, up to and including this word. Ten thousandth word, 'in', has 2 characters. 64097 characters in the sentence, up to and including this word. One hundred thousandth word, 'one', has 3 characters. 659455 characters in the sentence, up to and including this word. One millionth word, 'the', has 3 characters. 7113560 characters in the sentence, up to and including this word. Ten millionth word, 'thousand', has 8 characters. 70995729 characters in the sentence, up to and including this word.
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
Rust
<lang rust>struct NumberNames {
cardinal: &'static str, ordinal: &'static str,
}
impl NumberNames {
fn get_name(&self, ordinal: bool) -> &'static str { if ordinal { return self.ordinal; } self.cardinal }
}
const SMALL_NAMES: [NumberNames; 20] = [
NumberNames { cardinal: "zero", ordinal: "zeroth", }, NumberNames { cardinal: "one", ordinal: "first", }, NumberNames { cardinal: "two", ordinal: "second", }, NumberNames { cardinal: "three", ordinal: "third", }, NumberNames { cardinal: "four", ordinal: "fourth", }, NumberNames { cardinal: "five", ordinal: "fifth", }, NumberNames { cardinal: "six", ordinal: "sixth", }, NumberNames { cardinal: "seven", ordinal: "seventh", }, NumberNames { cardinal: "eight", ordinal: "eighth", }, NumberNames { cardinal: "nine", ordinal: "ninth", }, NumberNames { cardinal: "ten", ordinal: "tenth", }, NumberNames { cardinal: "eleven", ordinal: "eleventh", }, NumberNames { cardinal: "twelve", ordinal: "twelfth", }, NumberNames { cardinal: "thirteen", ordinal: "thirteenth", }, NumberNames { cardinal: "fourteen", ordinal: "fourteenth", }, NumberNames { cardinal: "fifteen", ordinal: "fifteenth", }, NumberNames { cardinal: "sixteen", ordinal: "sixteenth", }, NumberNames { cardinal: "seventeen", ordinal: "seventeenth", }, NumberNames { cardinal: "eighteen", ordinal: "eighteenth", }, NumberNames { cardinal: "nineteen", ordinal: "nineteenth", },
];
const TENS: [NumberNames; 8] = [
NumberNames { cardinal: "twenty", ordinal: "twentieth", }, NumberNames { cardinal: "thirty", ordinal: "thirtieth", }, NumberNames { cardinal: "forty", ordinal: "fortieth", }, NumberNames { cardinal: "fifty", ordinal: "fiftieth", }, NumberNames { cardinal: "sixty", ordinal: "sixtieth", }, NumberNames { cardinal: "seventy", ordinal: "seventieth", }, NumberNames { cardinal: "eighty", ordinal: "eightieth", }, NumberNames { cardinal: "ninety", ordinal: "ninetieth", },
];
struct NamedNumber {
cardinal: &'static str, ordinal: &'static str, number: usize,
}
impl NamedNumber {
fn get_name(&self, ordinal: bool) -> &'static str { if ordinal { return self.ordinal; } self.cardinal }
}
const N: usize = 7; const NAMED_NUMBERS: [NamedNumber; N] = [
NamedNumber { cardinal: "hundred", ordinal: "hundredth", number: 100, }, NamedNumber { cardinal: "thousand", ordinal: "thousandth", number: 1000, }, NamedNumber { cardinal: "million", ordinal: "millionth", number: 1000000, }, NamedNumber { cardinal: "billion", ordinal: "billionth", number: 1000000000, }, NamedNumber { cardinal: "trillion", ordinal: "trillionth", number: 1000000000000, }, NamedNumber { cardinal: "quadrillion", ordinal: "quadrillionth", number: 1000000000000000, }, NamedNumber { cardinal: "quintillion", ordinal: "quintillionth", number: 1000000000000000000, },
];
fn big_name(n: usize) -> &'static NamedNumber {
for i in 1..N { if n < NAMED_NUMBERS[i].number { return &NAMED_NUMBERS[i - 1]; } } &NAMED_NUMBERS[N - 1]
}
fn count_letters(s: &str) -> usize {
let mut count = 0; for c in s.chars() { if c.is_alphabetic() { count += 1; } } count
}
struct WordList {
words: Vec<(usize, usize)>, string: String,
}
impl WordList {
fn new() -> WordList { WordList { words: Vec::new(), string: String::new(), } } fn append(&mut self, s: &str) { let offset = self.string.len(); self.string.push_str(s); self.words.push((offset, offset + s.len())); } fn extend(&mut self, s: &str) { let len = self.words.len(); let mut w = &mut self.words[len - 1]; w.1 += s.len(); self.string.push_str(s); } fn len(&self) -> usize { self.words.len() } fn sentence_length(&self) -> usize { let n = self.words.len(); if n == 0 { return 0; } self.string.len() + n - 1 } fn get_word(&self, index: usize) -> &str { let w = &self.words[index]; &self.string[w.0..w.1] }
}
fn append_number_name(words: &mut WordList, n: usize, ordinal: bool) -> usize {
let mut count = 0; if n < 20 { words.append(SMALL_NAMES[n].get_name(ordinal)); count += 1; } else if n < 100 { if n % 10 == 0 { words.append(TENS[n / 10 - 2].get_name(ordinal)); } else { words.append(TENS[n / 10 - 2].get_name(false)); words.extend("-"); words.extend(SMALL_NAMES[n % 10].get_name(ordinal)); } count += 1; } else { let big = big_name(n); count += append_number_name(words, n / big.number, false); if n % big.number == 0 { words.append(big.get_name(ordinal)); count += 1; } else { words.append(big.get_name(false)); count += 1; count += append_number_name(words, n % big.number, ordinal); } } count
}
fn sentence(count: usize) -> WordList {
let mut result = WordList::new(); const WORDS: &'static [&'static str] = &[ "Four", "is", "the", "number", "of", "letters", "in", "the", "first", "word", "of", "this", "sentence,", ]; for s in WORDS { result.append(s); } let mut n = result.len(); let mut i = 1; while count > n { let count = count_letters(result.get_word(i)); n += append_number_name(&mut result, count, false); result.append("in"); result.append("the"); n += 2; n += append_number_name(&mut result, i + 1, true); result.extend(","); i += 1; } result
}
fn main() {
let mut n = 201; let s = sentence(n); println!("Number of letters in first {} words in the sequence:", n); for i in 0..n { if i != 0 { if i % 25 == 0 { println!(); } else { print!(" "); } } print!("{:2}", count_letters(s.get_word(i))); } println!(); println!("Sentence length: {}", s.sentence_length()); n = 1000; while n <= 10000000 { let s = sentence(n); let word = s.get_word(n - 1); print!( "The {}th word is '{}' and has {} letters. ", n, word, count_letters(word) ); println!("Sentence length: {}", s.sentence_length()); n *= 10; }
}</lang>
- Output:
Number of letters in first 201 words in the sequence: 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 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 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 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 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 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 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 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 11 Sentence length: 1203 The 1000th word is 'in' and has 2 letters. Sentence length: 6279 The 10000th word is 'in' and has 2 letters. Sentence length: 64140 The 100000th word is 'one' and has 3 letters. Sentence length: 659474 The 1000000th word is 'the' and has 3 letters. Sentence length: 7113621 The 10000000th word is 'thousand' and has 8 letters. Sentence length: 70995756
zkl
Uses the nth function from Spelling_of_ordinal_numbers#zkl <lang zkl> // Built the sentence in little chucks but only save the last one
// Save the word counts
fcn fourIsThe(text,numWords){
const rmc="-,"; seq:=(text - rmc).split().apply("len").copy(); // (4,2,3,6...) szs:=Data(numWords + 100,Int).howza(0).extend(seq); // bytes cnt,lastWords := seq.len(),""; total:=seed.len() - 1; // don't count trailing space
foreach idx in ([1..]){ sz:=szs[idx]; a,b := nth(sz,False),nth(idx+1); // "two","three hundred sixty-seventh" lastWords="%s in the %s, ".fmt(a,b); ws:=lastWords.counts(" ")[1]; // "five in the forty-ninth " --> 4 cnt+=ws; total+=lastWords.len(); lastWords.split().pump(szs.append,'-(rmc),"len"); if(cnt>=numWords){
if(cnt>numWords){ z,n:=lastWords.len(),z-2; do(cnt - numWords){ n=lastWords.rfind(" ",n) - 1; } lastWords=lastWords[0,n+1]; total-=(z - n); } break;
} } return(lastWords.strip(),szs,total);
} fcn lastWord(sentence){ sentence[sentence.rfind(" ")+1,*] }</lang> <lang zkl>var seed="Four is the number of letters in the first word of this sentence, "; sentence,szs,total := fourIsThe(seed,201); print(" 1:"); foreach n,x in ([1..201].zip(szs)){
print("%3d".fmt(x)); if(0 == n%25) print("\n%3d:".fmt(n+1));
} println("\nLength of above sentence: ",total);</lang>
- 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 above sentence: 1203
<lang zkl>n:=1000; do(5){
sentence,x,total := fourIsThe(seed,n); word:=lastWord(sentence); println("%,d words: \"%s\" [%d]. Length=%,d"
.fmt(n,word,word.len(),total));
n*=10;
}</lang>
- Output:
1,000 words: "in" [2]. Length=6,247 10,000 words: "in" [2]. Length=64,095 100,000 words: "one" [3]. Length=659,453 1,000,000 words: "the" [3]. Length=7,140,558 10,000,000 words: "thousand" [8]. Length=71,250,727