English cardinal anagrams
Certain numbers, when spelled out in their English cardinal representation, are anagrams of other numbers.
Some are very obvious: sixty-seven <=> seventy-six
Others are a little more subtle: one hundred twelve <=> two hundred eleven
- Task
- Find and display the first thirty numbers that are a member of English cardinal anagrams, starting from zero.
- Find and display the count of English cardinal anagrams from zero to one thousand.
- Find and display the largest group(s) of English cardinal anagrams from zero to one thousand.
- Stretch
- Find and display the count of English cardinal anagrams from zero to ten thousand, restricted to numbers within those bounds. (Ignore anagrams of numbers outside those bounds. E.G. 1010 <=> 10001)
- Find and display the largest group(s) of English cardinal anagrams from zero to ten thousand.
- See also
ALGOL 68
Using slightly modified code from the Four is magic task.
Note, the source of the RC ALGOL 68 sort library (sort.incl.a68) is on a separate page of Rosetta Code, see the above link.
BEGIN # construct number names from a number #
PR read "sort.incl.a68" PR # include sort utilities #
MODE NUMBER = LONG INT; # adjust to suit, must be at least 64 bits #
OP TOINT = ( NUMBER n )INT: SHORTEN n; # adjust to suit #
[]STRING units
= ( "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" );
[]STRING teens
= ( "ten", "eleven", "twelve", "thirteen", "fourteen"
, "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
);
[]STRING tens
= ( "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" );
[]STRING power suffix
= ( "thousand", "million", "billion", "trillion", "quadrillion", "quintillion" );
# returns c encoded as a = 1, b = 2, etc. c must be in "a".."z" #
OP LETTER = ( CHAR c )INT: ( ABS c - ABS "a" ) + 1;
# returns n converted to a number name, n must be in range 1-99 #
PROC two digits = ( INT n )STRING:
IF n < 10
THEN units[ n ]
ELIF n < 20
THEN teens[ n - 9 ]
ELIF INT last1 = n MOD 10;
last1 = 0
THEN tens[ ( n OVER 10 ) - 1 ]
ELSE tens[ ( n OVER 10 ) - 1 ] + " " + units[ last1 ]
FI # two digits # ;
# returns n converted to a number name, n must be in range 1-999 #
PROC three digits = ( INT n )STRING:
IF n < 100
THEN two digits( n )
ELIF STRING hundreds = units[ n OVER 100 ] + " hundred";
INT last2 = n MOD 100;
last2 = 0
THEN hundreds
ELSE hundreds + " and " + two digits( last2 )
FI # three digits # ;
# returns the "name" of n #
OP NAME = ( NUMBER n )STRING:
IF n < 0 THEN "negative " + NAME - n
ELIF n = 0 THEN "zero"
ELSE # have a positive number to name #
NUMBER v := n;
STRING result := "";
INT power pos := 0;
WHILE v /= 0 DO
IF INT v999 = TOINT ( v MOD 1000 );
v999 /= 0
THEN STRING component := three digits( v999 );
IF power pos > 0 THEN
component +:= " " + power suffix[ power pos ]
FI;
IF result /= "" THEN component +:= " " FI;
component +=: result
FI;
power pos +:= 1;
v OVERAB 1000
OD;
result
FI # NAME # ;
# returns the number name of n, only needed of NUMBER is not INT #
OP NAME = ( INT n )STRING: NAME NUMBER( n );
# returns a "hash" of s - s with the letters in order, spaces are ignored #
OP HASHOF = ( STRING s )STRING:
BEGIN
[ 1 : 26 ]INT counts; FOR i TO UPB counts DO counts[ i ] := 0 OD;
FOR i FROM LWB s TO UPB s DO
CHAR c = s[ i ];
IF c /= " " THEN counts[ LETTER c ] +:= 1 FI
OD;
STRING result := "";
FOR i FROM LETTER "a" TO LETTER "z" DO
IF counts[ i ] > 0 THEN result +:= counts[ i ] * REPR ( ABS "a" + i - 1 ) FI
OD;
result
END # HASHOF # ;
# mode to hold details of a possible cardinal name anagram #
MODE CARDINALANA = STRUCT( STRING h # "hash" of the name #
, INT n # the number #
, INT count # count of numbers with this hash #
);
# exchanges the values of swap a and with b #
OP =:= = ( REF CARDINALANA swap a, with b )VOID:
BEGIN CARDINALANA t = with b; with b := swap a; swap a := t END;
# in-place quick sort a[ lb : ub ] using qs lt for the comparisons #
PROC quicksort anagrams = ( REF[]CARDINALANA qs a
, INT lb, ub
, PROC(CARDINALANA,CARDINALANA)BOOL qs lt
) VOID:
IF ub <= lb
THEN SKIP # at most 1 element - no need to sort #
ELSE # more than one element, so must sort #
INT qs left := lb;
INT qs right := ub;
# choosing the middle element of the array as the pivot #
CARDINALANA pivot := qs a[ qs left + ( ( qs right + 1 ) - qs left ) OVER 2 ];
WHILE
WHILE IF qs left <= ub THEN qs lt( qs a[ qs left ], pivot ) ELSE FALSE FI
DO
qs left +:= 1
OD;
WHILE IF qs right >= lb THEN qs lt( pivot, qs a[ qs right ] ) ELSE FALSE FI
DO
qs right -:= 1
OD;
qs left <= qs right
DO
qs a[ qs left ] =:= qs a[ qs right ];
qs left +:= 1;
qs right -:= 1
OD;
quicksort anagrams( qs a, lb, qs right, qs lt );
quicksort anagrams( qs a, qs left, ub, qs lt )
FI # quicksort anagrams # ;
BEGIN
[]INT tests = ( 1 000, 10 000 );
FOR max pos FROM LWB tests TO UPB tests DO
INT max number = tests[ max pos ]; # largest number for this test #
# construct a table of the possible anagrams #
[ 0 : max number + 1 ]CARDINALANA anagram;
FOR n FROM 0 TO max number DO
h OF anagram[ n ] := HASHOF NAME n;
n OF anagram[ n ] := n;
count OF anagram[ n ] := 0
OD;
# add a final dummy element to simplify counting the anagrams #
h OF anagram[ max number + 1 ] := "z" * 26;
n OF anagram[ max number + 1 ] := -1;
count OF anagram[ max number + 1 ] := 0;
# sort the possible anagrams into "hash" and number order #
quicksort anagrams( anagram, 0, max number
, ( CARDINALANA a, b )BOOL: h OF a < h OF b
OR ( h OF a = h OF b AND n OF a < n OF b )
);
# add counts of each anagram to the table #
STRING max value := "";
INT prev start := LWB anagram;
STRING prev value := max value;
INT max count := 0, this count := 0;
FOR i FROM LWB anagram TO UPB anagram DO
STRING value := h OF anagram[ i ];
IF value = prev value THEN
this count +:= 1
ELSE
IF this count > max count THEN
max count := this count
FI;
FOR p FROM prev start TO i DO count OF anagram[ p ] := this count OD;
prev value := value;
prev start := i;
this count := 1
FI
OD;
PROC show group = ( []INT group )VOID:
BEGIN
INT pos := -1;
print( ( " [" ) );
FOR i FROM LWB group TO UPB group DO
IF ( pos +:= 1 ) = 10 THEN print( ( newline, " " ) ); pos := 0 FI;
print( ( " ", whole( group[ i ], IF group[ i ] < 100 THEN -3 ELSE 0 FI ) ) )
OD;
print( ( " ]", newline ) )
END # show group # ;
# show some features of the anagrams #
# count the anagrams #
INT anagram count := 0;
FOR i FROM LWB anagram + 1 TO UPB anagram DO
IF count OF anagram[ i ] > 1 AND h OF anagram[ i ] /= h OF anagram[ i - 1 ] THEN
anagram count +:= 1
FI
OD;
IF max pos = 1 THEN
# first test - show the first 30 anagrams #
[ 1 : max number ]INT first;
FOR i TO max number DO
first[ i ] := IF count OF anagram[ i ] > 1 THEN n OF anagram[ i ] ELSE max int FI
OD;
print( ( " the first 30 anagrams:", newline ) );
show group( ( QUICKSORT first )[ 1 : 30 ] )
FI;
print( ( "Up to ", whole( max number, 0 ) ) );
print( ( " there are ", whole( anagram count, 0 ), " anagrams", newline ) );
# show the largest group(s) of anagrams #
print( ( " the largest group(s) of anagrams:", newline ) );
[ 1 : max count ]INT a group;
INT a pos := 0;
prev value := "";
FOR i FROM LWB anagram TO UPB anagram DO
IF count OF anagram[ i ] = max count THEN
IF prev value = "" OR h OF anagram[ i ] /= prev value THEN
IF prev value /= "" THEN
show group( a group )
FI;
prev value := h OF anagram[ i ];
a pos := 0
FI;
a group[ a pos +:= 1 ] := n OF anagram[ i ]
FI
OD;
show group( a group )
OD
END
END
- Output:
the first 30 anagrams: [ 67 69 76 79 96 97 102 103 104 105 106 107 108 109 112 122 123 124 125 126 127 128 129 132 133 134 135 136 137 138 ] Up to 1000 there are 317 anagrams the largest group(s) of anagrams: [ 679 697 769 796 967 976 ] Up to 10000 there are 2534 anagrams the largest group(s) of anagrams: [ 3679 3697 3769 3796 3967 3976 6379 6397 6793 6973 7369 7396 7693 7963 9367 9376 9673 9763 ] [ 5679 5697 5769 5796 5967 5976 6579 6597 6795 6975 7569 7596 7695 7965 9567 9576 9675 9765 ] [ 6798 6879 6897 6978 7698 7869 7896 7968 8679 8697 8769 8796 8967 8976 9678 9768 9867 9876 ] [ 1679 1697 1769 1796 1967 1976 6179 6197 6791 6971 7169 7196 7691 7961 9167 9176 9671 9761 ] [ 4679 4697 4769 4796 4967 4976 6479 6497 6794 6974 7469 7496 7694 7964 9467 9476 9674 9764 ] [ 2679 2697 2769 2796 2967 2976 6279 6297 6792 6972 7269 7296 7692 7962 9267 9276 9672 9762 ]
Note the anagram groups are not sorted into starting number order, so the groups up to 10 000 are not in the same order as other samples.
C++
#include <algorithm>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <map>
#include <string>
#include <vector>
const std::vector<std::string> units = { "Zero", "One", "Two", "Three", "Four", "Five", "Six",
"Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen",
"Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen" };
const std::vector<std::string> tens =
{ "", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety" };
std::string convert(const uint32_t& n) { // Valid for positive integers ≤ 999_999_999
if ( n < 20 ) {
return units[n];
}
if ( n < 100 ) {
return tens[n / 10] + ( ( n % 10 > 0 ) ? " " + convert(n % 10) : "" );
}
if ( n < 1'000 ) {
return units[n / 100] + " Hundred" + ( ( n % 100 > 0 ) ? " and " + convert(n % 100) : "" );
}
if ( n < 1'000'000 ) {
return convert(n / 1'000) + " Thousand" + ( ( n % 1'000 > 0 ) ? " " + convert(n % 1'000) : "" );
}
return convert(n / 1'000'000) + " Million"
+ ( ( n % 1'000'000 > 0 ) ? " " + convert(n % 1'000'000) : "" );
}
std::string to_lower_case(const std::string& text) {
std::string result = text;
std::transform(result.begin(), result.end(), result.begin(), [](char ch) { return std::tolower(ch); });
return result;
}
void print_vector(std::vector<uint32_t> list) {
std::cout << "[";
for ( uint64_t i = 0; i < list.size() - 1; ++i ) {
std::cout << list[i] << ", ";
}
std::cout << list.back() << "]" << std::endl;
}
int main() {
for ( uint32_t limit : { 1'000, 10'000 } ) {
std::map<std::vector<char>, std::vector<uint32_t>> anagrams = { };
for ( uint32_t i = 0; i < limit; ++i ) {
std::string name = to_lower_case(convert(i));
std::vector<char> chars(name.begin(), name.end());
std::sort(chars.begin(), chars.end());
anagrams[chars].emplace_back(i);
}
if ( limit == 1'000 ) {
std::vector<uint32_t> allAnagrams = { };
for ( const auto& [key, value] : anagrams ) {
if ( value.size() > 1 ) {
allAnagrams.insert(allAnagrams.end(), value.begin(), value.end());
}
}
std::sort(allAnagrams.begin(), allAnagrams.end());
std::cout << "First 30 English cardinal anagrams:" << std::endl;
for ( uint32_t i = 0; i < 30; ++i ) {
std::cout << std::setw(3) << allAnagrams[i] << ( ( i % 10 == 9 ) ? "\n" : " " );
}
std::cout << std::endl;
}
const uint32_t count = std::count_if(anagrams.begin(), anagrams.end(),
[](const auto& pair) { return pair.second.size() > 1; });
std::cout << "Count of English cardinal anagrams up to 1000: " << count << std::endl << std::endl;
uint32_t max = 0;
std::vector<std::vector<uint32_t>> largest = { };
for ( const auto& [key, value] : anagrams ) {
if ( value.size() > max ) {
max = value.size();
largest = { value };
} else if ( value.size() == max ) {
largest.emplace_back(value);
}
}
std::cout << "Largest group(s) of English cardinal anagrams up to " << limit << ": " << std::endl;
std::sort(largest.begin(), largest.end(),
[](const std::vector<uint32_t>& a, const std::vector<uint32_t>& b) { return a[0] < b[0]; });
std::for_each(largest.begin(), largest.end(), print_vector);
std::cout << std::endl;
}
}
- Output:
First 30 English cardinal anagrams: 67 69 76 79 96 97 102 103 104 105 106 107 108 109 112 122 123 124 125 126 127 128 129 132 133 134 135 136 137 138 Count of English cardinal anagrams up to 1000: 317 Largest group(s) of English cardinal anagrams up to 1000: [679, 697, 769, 796, 967, 976] Count of English cardinal anagrams up to 1000: 2534 Largest group(s) of English cardinal anagrams up to 10000: [1679, 1697, 1769, 1796, 1967, 1976, 6179, 6197, 6791, 6971, 7169, 7196, 7691, 7961, 9167, 9176, 9671, 9761] [2679, 2697, 2769, 2796, 2967, 2976, 6279, 6297, 6792, 6972, 7269, 7296, 7692, 7962, 9267, 9276, 9672, 9762] [3679, 3697, 3769, 3796, 3967, 3976, 6379, 6397, 6793, 6973, 7369, 7396, 7693, 7963, 9367, 9376, 9673, 9763] [4679, 4697, 4769, 4796, 4967, 4976, 6479, 6497, 6794, 6974, 7469, 7496, 7694, 7964, 9467, 9476, 9674, 9764] [5679, 5697, 5769, 5796, 5967, 5976, 6579, 6597, 6795, 6975, 7569, 7596, 7695, 7965, 9567, 9576, 9675, 9765] [6798, 6879, 6897, 6978, 7698, 7869, 7896, 7968, 8679, 8697, 8769, 8796, 8967, 8976, 9678, 9768, 9867, 9876]
FreeBASIC
#define floor(x) ((x*2.0-0.5) Shr 1)
#define MIN(a, b) iif((a) < (b), (a), (b))
Sub SortInt(array() As Integer)
Static As Integer i, j, mn
Dim As Integer lb = Lbound(array), ub = Ubound(array)
For i = lb To ub - 1
mn = i
For j = i + 1 To ub
If array(j) < array(mn) Then mn = j
Next j
Swap array(mn), array(i)
Next i
End Sub
Sub SortStr(array() As String)
Dim As Integer i, j
Dim As Integer lb = Lbound(array), ub = Ubound(array)
For i = lb To ub - 1
For j = i + 1 To ub
If array(i) > array(j) Then Swap array(i), array(j)
Next j
Next i
End Sub
Function say(n As Integer) As String
Dim As String small(0 To 19) = { _
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", _
"nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", _
"sixteen", "seventeen", "eighteen", "nineteen"}
Dim As String tens(0 To 9) = { _
"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"}
Dim As String illions(0 To 5) = { _
"", " thousand", " million", " billion", " trillion", " quadrillion"}
Dim As Integer s, p, i
Dim As String t = "", sx, ix
If (n < 0) Then
t = "negative "
n = -n
End If
If (n < 20) Then
t &= small(n)
Elseif (n < 100) Then
t &= tens(floor(n / 10))
s = n Mod 10
If (s > 0) Then t &= "-" & small(s)
Elseif (n < 1000) Then
t &= small(floor(n / 100)) & " hundred"
s = n Mod 100
If (s > 0) Then t &= " " & say(s)
Else
sx = ""
i = 0
While (n > 0)
p = n Mod 1000
n = floor(n / 1000)
If (p > 0) Then
ix = say(p) & illions(i)
If (sx <> "") Then ix &= " " & sx
sx = ix
End If
i += 1
Wend
t &= sx
End If
Return t
End Function
Function CleanString(s As String) As String ' REPLACE
Dim As String result = ""
For i As Integer = 1 To Len(s)
If Mid(s, i, 1) <> " " And Mid(s, i, 1) <> "-" Then
result &= Mid(s, i, 1)
End If
Next
Return result
End Function
Sub ParseValues(s As String, values() As Integer)
' Divide una cadena en valores enteros sin usar SPLIT
Dim As Integer cnt = 0, start = 1, commaPos
Do
commaPos = Instr(start, s, ",")
If commaPos = 0 Then commaPos = Len(s) + 1
Redim Preserve values(cnt)
values(cnt) = Val(Mid(s, start, commaPos - start))
cnt += 1
start = commaPos + 1
Loop While commaPos <= Len(s)
End Sub
Dim As Integer limit, i, j, k, max
Dim As Integer largest(),all(), values()
Dim As String ana(), anaMap(), keyArray()
For limit = 1000 To 10000 Step 9000
Redim ana(0)
Redim anaMap(0)
For i = 0 To limit
Dim As String key = CleanString(say(i))
Redim keyArray(Len(key) - 1)
For j = 0 To Len(key) - 1
keyArray(j) = Mid(key, j + 1, 1)
Next j
SortStr(keyArray())
key = ""
For j = Lbound(keyArray) To Ubound(keyArray)
key &= keyArray(j)
Next j
Dim As Integer found = -1
For k = 0 To Ubound(ana)
If ana(k) = key Then
found = k
Exit For
End If
Next k
If found = -1 Then
Redim Preserve ana(Ubound(ana) + 1)
ana(Ubound(ana)) = key
Redim Preserve anaMap(Ubound(anaMap) + 1)
anaMap(Ubound(anaMap)) = Str(i)
Else
anaMap(found) &= "," & Str(i)
End If
Next i
If (limit = 1000) Then
Redim all(0)
For i As Integer = 0 To Ubound(anaMap)
Dim values() As Integer
ParseValues(anaMap(i), values())
If Ubound(values) > 0 Then
For w As Integer = 0 To Ubound(values)
Redim Preserve all(Ubound(all) + 1)
all(Ubound(all)) = values(w)
Next w
End If
Next i
SortInt(all())
Print "First 30 English cardinal anagrams:"
For j = 1 To MIN(30, Ubound(all))
Print Using "####"; all(j);
If j Mod 10 = 0 Then Print
Next j
End If
Dim As Integer cnt = 0
For i = 0 To Ubound(anaMap)
ParseValues(anaMap(i), values())
If Ubound(values) > 0 Then cnt += 1
Next i
Print Using !"\nCount of English cardinal anagrams up to ##,###: #,###"; limit; cnt
max = 0
Redim largest(0)
For i = 0 To Ubound(anaMap)
ParseValues(anaMap(i), values())
If Ubound(values) > max Then
max = Ubound(values)
Redim largest(Ubound(values))
For j = 0 To Ubound(values)
largest(j) = values(j)
Next j
Elseif Ubound(values) = max Then
Dim As Integer oldSize = Ubound(largest)
Redim Preserve largest(oldSize + Ubound(values) + 1)
For j = 0 To Ubound(values)
largest(oldSize + j + 1) = values(j)
Next j
End If
Next i
Print !"\nLargest group(s) of English cardinal anagrams up to"; limit; ":"
For k As Integer = 0 To Ubound(largest)
Print largest(k);
If k < Ubound(largest) Then Print " ";
If (k+1) Mod 18 = 0 Then Print
Next k
If (limit = 1000) Then Print
Next limit
Sleep
- Output:
First 30 English cardinal anagrams: 67 69 76 79 96 97 102 103 104 105 106 107 108 109 112 122 123 124 125 126 127 128 129 132 133 134 135 136 137 138 Count of English cardinal anagrams up to 1,000: 317 Largest group(s) of English cardinal anagrams up to 1000: 679 697 769 796 967 976 Count of English cardinal anagrams up to 10,000: 2,534 Largest group(s) of English cardinal anagrams up to 10000: 1679 1697 1769 1796 1967 1976 6179 6197 6791 6971 7169 7196 7691 7961 9167 9176 9671 9761 2679 2697 2769 2796 2967 2976 6279 6297 6792 6972 7269 7296 7692 7962 9267 9276 9672 9762 3679 3697 3769 3796 3967 3976 6379 6397 6793 6973 7369 7396 7693 7963 9367 9376 9673 9763 4679 4697 4769 4796 4967 4976 6479 6497 6794 6974 7469 7496 7694 7964 9467 9476 9674 9764 5679 5697 5769 5796 5967 5976 6579 6597 6795 6975 7569 7596 7695 7965 9567 9576 9675 9765 6798 6879 6897 6978 7698 7869 7896 7968 8679 8697 8769 8796 8967 8976 9678 9768 9867 9876
J
Using the definitions at Number_names#J and
ukgram=: /:~@uk&.>
sample=: I.(e. ~. #~ 1<#/.~)ukgram i. 1e6
sam1e3=: I.(e. ~. #~ 1<#/.~)ukgram i. 1e3
sam1e4=: I.(e. ~. #~ 1<#/.~)ukgram i. 1e4
largegroups=: {{
tokens=. /:~@uk&.> y
utokens=. ~. tokens
ucounts=. #/.~ tokens
uids=. utokens #~ (=>./) ucounts
>}.y </.~ uids i. tokens
}}
We get:
3 10$ sample
67 69 76 79 96 97 102 103 104 105
106 107 108 109 112 122 123 124 125 126
127 128 129 132 133 134 135 136 137 138
+/1000>:sample NB. count of values in OEIS::A169936 less than 1000
680
#~.ukgram (#~ 1000>:])sample NB. count of distinct anagrams for those values
317
largegroups (#~ 1000&>:) sample
679 697 769 796 967 976
Stretch:
If we consider all values in values in OEIS:A169936 which are less than 1e4
+/10000>:sample NB. distinct members in subsequence
9662
#~.ukgram (#~ 10000>:])sample NB. distinct anagrams in subsequence
2968
largegroups (#~ 10000&>:) sample NB. anagram groups with most members in subsequence
1679 1697 1769 1796 1967 1976 6179 6197 6791 6971 7169 7196 7691 7961 9167 9176 9671 9761
2679 2697 2769 2796 2967 2976 6279 6297 6792 6972 7269 7296 7692 7962 9267 9276 9672 9762
3679 3697 3769 3796 3967 3976 6379 6397 6793 6973 7369 7396 7693 7963 9367 9376 9673 9763
4679 4697 4769 4796 4967 4976 6479 6497 6794 6974 7469 7496 7694 7964 9467 9476 9674 9764
5679 5697 5769 5796 5967 5976 6579 6597 6795 6975 7569 7596 7695 7965 9567 9576 9675 9765
6798 6879 6897 6978 7698 7869 7896 7968 8679 8697 8769 8796 8967 8976 9678 9768 9867 9876
If we explicitly exclude anagrams whose only partner is greater than 1e4, we get a slightly smaller subsequence:
#sam1e4
9228
#~.ukgram sam1e4
2534
Note however that for values less than 1000, every member of the OEIS:A169936 sequence had a partner which was also less than 1000:
#sam1e3
680
+/1000>:sample
680
Java
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public final class EnglishCardinalAnagrams {
public static void main(String[] args) {
for ( int limit : List.of( 1_000, 10_000 ) ) {
Map<List<Character>, List<Integer>> anagrams = new HashMap<List<Character>, List<Integer>>();
for ( int i = 0; i < limit; i++ ) {
String name = NumberToWordsConverter.convert(i).toLowerCase();
List<Character> chars = name.chars().mapToObj( ch -> (char) ch ).sorted().toList();
anagrams.computeIfAbsent(chars, k -> new ArrayList<Integer>() ).add(i);
}
if ( limit == 1_000 ) {
List<Integer> allAnagrams = anagrams.values().stream().filter( list -> list.size() > 1 )
.flatMap(Collection::stream).sorted().toList();
System.out.println("First 30 English cardinal anagrams:");
for ( int i = 0; i < 30; i++ ) {
System.out.print(String.format("%3d%s", allAnagrams.get(i),
( i % 10 == 9 ) ? "\n" : " " ));
}
System.out.println();
}
final long count = anagrams.values().stream().filter( list -> list.size() > 1 ).count();
System.out.println("Count of English cardinal anagrams up to 1000: " + count);
System.out.println();
int max = 0;
List<List<Integer>> largest = new ArrayList<List<Integer>>();
for ( List<Integer> list : anagrams.values() ) {
if ( list.size() > max ) {
max = list.size();
largest = Stream.of( list ).limit(1).collect(Collectors.toList());
} else if ( list.size() == max ) {
largest.addLast(list);
}
}
System.out.println("Largest group(s) of English cardinal anagrams up to " + limit + ": ");
largest.sort( (list1, list2) -> list1.getFirst().compareTo(list2.getFirst()));
largest.forEach(System.out::println);
System.out.println();
}
}
private static final class NumberToWordsConverter { // Valid for positive integers ≤ 999_999_999
public static String convert(int n) {
if ( n < 20 ) {
return units[n];
}
if ( n < 100 ) {
return tens[n / 10] + ( ( n % 10 > 0 ) ? " " + convert(n % 10) : "" );
}
if ( n < 1_000 ) {
return units[n / 100] + " Hundred" + ( ( n % 100 > 0 ) ? " and " + convert(n % 100) : "" );
}
if ( n < 1_000_000 ) {
return convert(n / 1_000) + " Thousand"
+ ( ( n % 1_000 > 0 ) ? " " + convert(n % 1_000) : "" );
}
return convert(n / 1_000_000) + " Million"
+ ( ( n % 1_000_000 > 0 ) ? " " + convert(n % 1_000_000) : "" );
}
private static final String[] units = { "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 =
{ "", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety" };
}
}
- Output:
First 30 English cardinal anagrams: 67 69 76 79 96 97 102 103 104 105 106 107 108 109 112 122 123 124 125 126 127 128 129 132 133 134 135 136 137 138 Count of English cardinal anagrams up to 1000: 317 Largest group(s) of English cardinal anagrams up to 1000: [679, 697, 769, 796, 967, 976] Count of English cardinal anagrams up to 1000: 2534 Largest group(s) of English cardinal anagrams up to 10000: [1679, 1697, 1769, 1796, 1967, 1976, 6179, 6197, 6791, 6971, 7169, 7196, 7691, 7961, 9167, 9176, 9671, 9761] [2679, 2697, 2769, 2796, 2967, 2976, 6279, 6297, 6792, 6972, 7269, 7296, 7692, 7962, 9267, 9276, 9672, 9762] [3679, 3697, 3769, 3796, 3967, 3976, 6379, 6397, 6793, 6973, 7369, 7396, 7693, 7963, 9367, 9376, 9673, 9763] [4679, 4697, 4769, 4796, 4967, 4976, 6479, 6497, 6794, 6974, 7469, 7496, 7694, 7964, 9467, 9476, 9674, 9764] [5679, 5697, 5769, 5796, 5967, 5976, 6579, 6597, 6795, 6975, 7569, 7596, 7695, 7965, 9567, 9576, 9675, 9765] [6798, 6879, 6897, 6978, 7698, 7869, 7896, 7968, 8679, 8697, 8769, 8796, 8967, 8976, 9678, 9768, 9867, 9876]
Julia
import SpelledOut: spelled_out
import Counters: counter
languages = Dict("English" => :en, "Spanish" => :es, "Portuguese" => :pt_BR)
""" remove diacritical marks, as anagrams use only standard alphabet """
undiacritical(s) = replace(replace(replace(s, r"[éêé]" => "e"), "ã" => "a"), r"[óõ]" => "o")
""" get the letter frequencies as an anagram representation of string str """
function anarep(str)
s = undiacritical(lowercase(str))
return [count(c, s) for c in 'a':'z'] # ignores spaces, hyphens, capitalization
end
""" task at rosettacode.org/wiki/English_cardinal_anagrams """
function process_task(maxrange, showfirst30, lang = "English")
numstrings = map(n -> spelled_out(n, lang=languages[lang]), 0:maxrange)
numreps = map(anarep, numstrings)
anadict = counter(numreps)
counts = [anadict[numreps[i]] for i in 1:maxrange]
if showfirst30
println("First 30 $lang cardinal anagrams:")
i, printed = 1, 0
while i < maxrange && printed < 30
if counts[i] > 1
printed += 1
print(rpad(i, 4), printed % 10 == 0 ? "\n" : "")
end
i += 1
end
end
print("\nCount of $lang cardinal anagrams up to $maxrange: ")
println(count(values(anadict) .> 1))
println("\nLargest group(s) of $lang cardinal anagrams up to $maxrange:")
maxcount = maximum(counts)
for r in unique([numreps[i] for i in 1:maxrange if counts[i] == maxcount])
println(findall(==(r), numreps))
end
end
process_task(1000, true)
process_task(10000, false)
process_task(10000, false, "Spanish")
process_task(10000, false, "Portuguese")
- Output:
First 30 English cardinal anagrams: 67 69 76 79 96 97 102 103 104 105 106 107 108 109 112 122 123 124 125 126 127 128 129 132 133 134 135 136 137 138 Count of English cardinal anagrams up to 1000: 317 Largest group(s) of English cardinal anagrams up to 1000: [679, 697, 769, 796, 967, 976] Count of English cardinal anagrams up to 10000: 2534 Largest group(s) of English cardinal anagrams up to 10000: [1679, 1697, 1769, 1796, 1967, 1976, 6179, 6197, 6791, 6971, 7169, 7196, 7691, 7961, 9167, 9176, 9671, 9761] [2679, 2697, 2769, 2796, 2967, 2976, 6279, 6297, 6792, 6972, 7269, 7296, 7692, 7962, 9267, 9276, 9672, 9762] [3679, 3697, 3769, 3796, 3967, 3976, 6379, 6397, 6793, 6973, 7369, 7396, 7693, 7963, 9367, 9376, 9673, 9763] [4679, 4697, 4769, 4796, 4967, 4976, 6479, 6497, 6794, 6974, 7469, 7496, 7694, 7964, 9467, 9476, 9674, 9764] [5679, 5697, 5769, 5796, 5967, 5976, 6579, 6597, 6795, 6975, 7569, 7596, 7695, 7965, 9567, 9576, 9675, 9765] [6798, 6879, 6897, 6978, 7698, 7869, 7896, 7968, 8679, 8697, 8769, 8796, 8967, 8976, 9678, 9768, 9867, 9876] Count of Spanish cardinal anagrams up to 10000: 2635 Largest group(s) of Spanish cardinal anagrams up to 10000: [2304, 2403, 3204, 3402, 4203, 4302] [2306, 2603, 3206, 3602, 6203, 6302] [2308, 2803, 3208, 3802, 8203, 8302] [2324, 2423, 3224, 3422, 4223, 4322] [2326, 2623, 3226, 3622, 6223, 6322] [2328, 2823, 3228, 3822, 8223, 8322] [2334, 2433, 3234, 3432, 4233, 4332] [2336, 2633, 3236, 3632, 6233, 6332] [2338, 2833, 3238, 3832, 8233, 8332] [2344, 2443, 3244, 3442, 4243, 4342] [2346, 2643, 3246, 3642, 6243, 6342] [2348, 2843, 3248, 3842, 8243, 8342] [2354, 2453, 3254, 3452, 4253, 4352] [2356, 2653, 3256, 3652, 6253, 6352] [2358, 2853, 3258, 3852, 8253, 8352] [2364, 2463, 3264, 3462, 4263, 4362] [2366, 2663, 3266, 3662, 6263, 6362] [2368, 2863, 3268, 3862, 8263, 8362] [2374, 2473, 3274, 3472, 4273, 4372] [2376, 2673, 3276, 3672, 6273, 6372] [2378, 2873, 3278, 3872, 8273, 8372] [2384, 2483, 3284, 3482, 4283, 4382] [2386, 2683, 3286, 3682, 6283, 6382] [2388, 2883, 3288, 3882, 8283, 8382] [2394, 2493, 3294, 3492, 4293, 4392] [2396, 2693, 3296, 3692, 6293, 6392] [2398, 2893, 3298, 3892, 8293, 8392] [2406, 2604, 4206, 4602, 6204, 6402] [2408, 2804, 4208, 4802, 8204, 8402] [2426, 2624, 4226, 4622, 6224, 6422] [2428, 2824, 4228, 4822, 8224, 8422] [2436, 2634, 4236, 4632, 6234, 6432] [2438, 2834, 4238, 4832, 8234, 8432] [2446, 2644, 4246, 4642, 6244, 6442] [2448, 2844, 4248, 4842, 8244, 8442] [2456, 2654, 4256, 4652, 6254, 6452] [2458, 2854, 4258, 4852, 8254, 8452] [2466, 2664, 4266, 4662, 6264, 6462] [2468, 2864, 4268, 4862, 8264, 8462] [2476, 2674, 4276, 4672, 6274, 6472] [2478, 2874, 4278, 4872, 8274, 8472] [2486, 2684, 4286, 4682, 6284, 6482] [2488, 2884, 4288, 4882, 8284, 8482] [2496, 2694, 4296, 4692, 6294, 6492] [2498, 2894, 4298, 4892, 8294, 8492] [2608, 2806, 6208, 6802, 8206, 8602] [2628, 2826, 6228, 6822, 8226, 8622] [2638, 2836, 6238, 6832, 8236, 8632] [2648, 2846, 6248, 6842, 8246, 8642] [2658, 2856, 6258, 6852, 8256, 8652] [2668, 2866, 6268, 6862, 8266, 8662] [2678, 2876, 6278, 6872, 8276, 8672] [2688, 2886, 6288, 6882, 8286, 8682] [2698, 2896, 6298, 6892, 8296, 8692] [3406, 3604, 4306, 4603, 6304, 6403] [3408, 3804, 4308, 4803, 8304, 8403] [3426, 3624, 4326, 4623, 6324, 6423] [3428, 3824, 4328, 4823, 8324, 8423] [3436, 3634, 4336, 4633, 6334, 6433] [3438, 3834, 4338, 4833, 8334, 8433] [3446, 3644, 4346, 4643, 6344, 6443] [3448, 3844, 4348, 4843, 8344, 8443] [3456, 3654, 4356, 4653, 6354, 6453] [3458, 3854, 4358, 4853, 8354, 8453] [3466, 3664, 4366, 4663, 6364, 6463] [3468, 3864, 4368, 4863, 8364, 8463] [3476, 3674, 4376, 4673, 6374, 6473] [3478, 3874, 4378, 4873, 8374, 8473] [3486, 3684, 4386, 4683, 6384, 6483] [3488, 3884, 4388, 4883, 8384, 8483] [3496, 3694, 4396, 4693, 6394, 6493] [3498, 3894, 4398, 4893, 8394, 8493] [3608, 3806, 6308, 6803, 8306, 8603] [3628, 3826, 6328, 6823, 8326, 8623] [3638, 3836, 6338, 6833, 8336, 8633] [3648, 3846, 6348, 6843, 8346, 8643] [3658, 3856, 6358, 6853, 8356, 8653] [3668, 3866, 6368, 6863, 8366, 8663] [3678, 3876, 6378, 6873, 8376, 8673] [3688, 3886, 6388, 6883, 8386, 8683] [3698, 3896, 6398, 6893, 8396, 8693] [4608, 4806, 6408, 6804, 8406, 8604] [4628, 4826, 6428, 6824, 8426, 8624] [4638, 4836, 6438, 6834, 8436, 8634] [4648, 4846, 6448, 6844, 8446, 8644] [4658, 4856, 6458, 6854, 8456, 8654] [4668, 4866, 6468, 6864, 8466, 8664] [4678, 4876, 6478, 6874, 8476, 8674] [4688, 4886, 6488, 6884, 8486, 8684] [4698, 4896, 6498, 6894, 8496, 8694] Count of Portuguese cardinal anagrams up to 10000: 2505 Largest group(s) of Portuguese cardinal anagrams up to 10000: [4679, 4697, 4796, 4976, 6479, 6497, 6794, 6974, 7496, 7694, 9476, 9674] [4798, 4879, 4897, 4978, 7498, 7894, 8479, 8497, 8794, 8974, 9478, 9874] [6798, 6879, 6897, 6978, 7698, 7896, 8679, 8697, 8796, 8976, 9678, 9876]
Perl
use strict; use warnings;
use feature <say postderef>;
use List::AllUtils 'max_by';
use Lingua::EN::Numbers 'num2en';
for my $limit (1e3, 1e4) {
my(%E,@E);
push $E{ join '', sort split '', num2en($_) }->@*, $_ for 0..$limit;
for (keys %E) { delete $E{$_} if $E{$_}->@* < 2 }
@E = sort { $a <=> $b } map { @$_ } values %E;
say 'First 30 English cardinal anagrams:' . join ' ', @E[0..29] if $limit == 1e3;
say "\nCount of English cardinal anagrams up to $limit: " . keys %E;
say "\nLargest group(s) of English cardinal anagrams up to $limit";
say join ' ', $E{$_}->@* for max_by {f $E{$_}->@* } keys %E;
}
- Output:
First 30 English cardinal anagrams: 67 69 76 79 96 97 102 103 104 105 106 107 108 109 112 122 123 124 125 126 127 128 129 132 133 134 135 136 137 138 Count of English cardinal anagrams up to 1000: 317 Largest group(s) of English cardinal anagrams up to 1000 679 697 769 796 967 976 Count of English cardinal anagrams up to 10000: 2534 Largest group(s) of English cardinal anagrams up to 10000 5679 5697 5769 5796 5967 5976 6579 6597 6795 6975 7569 7596 7695 7965 9567 9576 9675 9765 4679 4697 4769 4796 4967 4976 6479 6497 6794 6974 7469 7496 7694 7964 9467 9476 9674 9764 3679 3697 3769 3796 3967 3976 6379 6397 6793 6973 7369 7396 7693 7963 9367 9376 9673 9763 1679 1697 1769 1796 1967 1976 6179 6197 6791 6971 7169 7196 7691 7961 9167 9176 9671 9761 2679 2697 2769 2796 2967 2976 6279 6297 6792 6972 7269 7296 7692 7962 9267 9276 9672 9762 6798 6879 6897 6978 7698 7869 7896 7968 8679 8697 8769 8796 8967 8976 9678 9768 9867 9876
Phix
with javascript_semantics
for limit in {1000, 10000} do
sequence ana = {}, ani = {}
for i=0 to limit do
string key = trim(sort(ordinal(i,true)))
integer k = find(key,ana)
if k then
ani[k] &= i
else
ana = append(ana,key)
ani = append(ani,{i})
end if
end for
sequence lengths = apply(ani,length)
if limit==1000 then
sequence all = {}
for i,l in lengths do
if l>1 then
all = append(all,ani[i])
if length(all)>=30 then exit end if
end if
end for
all = sort(flatten(all))[1..30]
printf(1,"First 30 English cardinal anagrams:\n%s\n",
join_by(all,1,10," ",fmt:="%3d"))
end if
printf(1,"Count of English cardinal anagrams up to %,d: %,d\n\n",
{limit, length(filter(lengths,">",1))})
integer maxlen = max(lengths)
sequence biggest = {}
for i,l in lengths do
if l=maxlen then
biggest = append(biggest,"["&join(ani[i]," ",fmt:="%d")&"]")
end if
end for
printf(1,"Largest group%s of English cardinal anagrams up to %,d:\n %s\n\n",
{iff(length(biggest)=1?"":"s"),limit,join(biggest,"\n ")})
end for
- Output:
First 30 English cardinal anagrams: 67 69 76 79 96 97 102 103 104 105 106 107 108 109 112 122 123 124 125 126 127 128 129 132 133 134 135 136 137 138 Count of English cardinal anagrams up to 1,000: 317 Largest group of English cardinal anagrams up to 1,000: [679 697 769 796 967 976] Count of English cardinal anagrams up to 10,000: 2,534 Largest groups of English cardinal anagrams up to 10,000: [1679 1697 1769 1796 1967 1976 6179 6197 6791 6971 7169 7196 7691 7961 9167 9176 9671 9761] [2679 2697 2769 2796 2967 2976 6279 6297 6792 6972 7269 7296 7692 7962 9267 9276 9672 9762] [3679 3697 3769 3796 3967 3976 6379 6397 6793 6973 7369 7396 7693 7963 9367 9376 9673 9763] [4679 4697 4769 4796 4967 4976 6479 6497 6794 6974 7469 7496 7694 7964 9467 9476 9674 9764] [5679 5697 5769 5796 5967 5976 6579 6597 6795 6975 7569 7596 7695 7965 9567 9576 9675 9765] [6798 6879 6897 6978 7698 7869 7896 7968 8679 8697 8769 8796 8967 8976 9678 9768 9867 9876]
Python
""" rosettacode.org/wiki/English_cardinal_anagrams """
from collections import Counter
from num2words import num2words
def anagrammed(astring):
""" Get the letter counts of astring for use as an anagram representation.
Ignores spaces, hyphens, capitalization """
lstr = astring.lower()
charcounts = [sum(c == letter for c in lstr)
for letter in 'abcdefghijklmnopqrstuvwxyz']
return ''.join([f'{j:0>2d}' for j in charcounts])
def process_task(maxrange, showfirst30=True):
""" task at rosettacode.org/wiki/English_cardinal_anagrams """
numwords = [num2words(n) for n in range(maxrange+1)]
anastrings = [anagrammed(astr) for astr in numwords]
rep_to_count = Counter(anastrings)
counts = [rep_to_count[anastrings[i]] for i in range(maxrange+1)]
if showfirst30:
print("First 30 English cardinal anagrams:")
i, printed = 1, 0
while i < maxrange and printed < 30:
if counts[i] > 1:
printed += 1
print(f'{i:4}', end='\n' if printed % 10 == 0 else '')
i += 1
print(f'\nCount of English cardinal anagrams up to {maxrange}: ', end='')
print(sum(n > 1 for n in rep_to_count.values()))
print(f'\nLargest group(s) of English cardinal anagrams up to {maxrange}:')
maxcount = max(counts)
for rep in set(anastrings[i] for i in range(maxrange+1) if counts[i] == maxcount):
print([i for i in range(maxrange+1) if anastrings[i] == rep])
process_task(1000)
process_task(10000, False)
- Output:
First 30 English cardinal anagrams: 67 69 76 79 96 97 102 103 104 105 106 107 108 109 112 122 123 124 125 126 127 128 129 132 133 134 135 136 137 138 Count of English cardinal anagrams up to 1000: 317 Largest group(s) of English cardinal anagrams up to 1000: [679, 697, 769, 796, 967, 976] Count of English cardinal anagrams up to 10000: 2534 Largest group(s) of English cardinal anagrams up to 10000: [4679, 4697, 4769, 4796, 4967, 4976, 6479, 6497, 6794, 6974, 7469, 7496, 7694, 7964, 9467, 9476, 9674, 9764] [3679, 3697, 3769, 3796, 3967, 3976, 6379, 6397, 6793, 6973, 7369, 7396, 7693, 7963, 9367, 9376, 9673, 9763] [5679, 5697, 5769, 5796, 5967, 5976, 6579, 6597, 6795, 6975, 7569, 7596, 7695, 7965, 9567, 9576, 9675, 9765] [1679, 1697, 1769, 1796, 1967, 1976, 6179, 6197, 6791, 6971, 7169, 7196, 7691, 7961, 9167, 9176, 9671, 9761] [6798, 6879, 6897, 6978, 7698, 7869, 7896, 7968, 8679, 8697, 8769, 8796, 8967, 8976, 9678, 9768, 9867, 9876] [2679, 2697, 2769, 2796, 2967, 2976, 6279, 6297, 6792, 6972, 7269, 7296, 7692, 7962, 9267, 9276, 9672, 9762]
Quackery
name$
is defined at Number names#Quackery.
[ stack ] is bunches ( --> s )
[ stack ] is sames ( --> s )
[ [] swap witheach
[ dup space = iff drop done
dup char , = iff drop done
join ] ] is strip ( $ --> $ )
[ [] swap times
[ i^ name$ strip sort
nested i^ join
nested join ]
sortwith
[ 0 peek swap 0 peek $< ]
[] bunches put
[] sames put
behead swap witheach
[ over 0 peek
over 0 peek = iff
[ 1 peek sames gather ]
done
sames take nested bunches gather
dup 1 peek nested sames put
nip ]
drop
sames take nested bunches gather
bunches take
[] swap
witheach [ dup size 2 < iff
drop else [ nested join ] ] ] is cardinagrams ( n --> [ )
1000 cardinagrams
say "First thirty 30 cardinal anagrams:" cr
[] over witheach join
sort 30 split drop sort echo cr cr
dup
say "Number of cardinal anagrams up to 1000: "
size echo cr cr
0 over witheach [ size max ]
say "Largest group(s) therein :" cr
swap witheach
[ 2dup size != iff drop done
echo cr ]
drop
cr
10000 cardinagrams
say "Number of cardinal anagrams up to 10000: "
dup size echo cr cr
0 over witheach [ size max ]
say "Largest group(s) therein:" cr
swap witheach
[ 2dup size != iff drop done
echo cr ]
drop
- Output:
First thirty 30 cardinal anagrams: [ 67 69 76 79 96 97 102 103 104 105 106 107 108 109 112 122 123 124 125 126 127 128 129 132 133 134 135 136 137 138 ] Number of cardinal anagrams up to 1000: 317 Largest group(s) therein : [ 679 697 769 796 967 976 ] Number of cardinal anagrams up to 10000: 2534 Largest group(s) therein: [ 3679 3697 3769 3796 3967 3976 6379 6397 6793 6973 7369 7396 7693 7963 9367 9376 9673 9763 ] [ 5679 5697 5769 5796 5967 5976 6579 6597 6795 6975 7569 7596 7695 7965 9567 9576 9675 9765 ] [ 6798 6879 6897 6978 7698 7869 7896 7968 8679 8697 8769 8796 8967 8976 9678 9768 9867 9876 ] [ 1679 1697 1769 1796 1967 1976 6179 6197 6791 6971 7169 7196 7691 7961 9167 9176 9671 9761 ] [ 4679 4697 4769 4796 4967 4976 6479 6497 6794 6974 7469 7496 7694 7964 9467 9476 9674 9764 ] [ 2679 2697 2769 2796 2967 2976 6279 6297 6792 6972 7269 7296 7692 7962 9267 9276 9672 9762 ]
Raku
use Lingua::EN::Numbers;
use List::Allmax;
for 1_000, 10_000 {
my %eca; # English cardinal anagrams
(^$_).map: { %eca{.&cardinal.comb.sort.join}.push: $_ }
once say "\nFirst 30 English cardinal anagrams:\n " ~
(sort flat %eca.grep(+*.value > 1)».value.map: *.flat)[^30]\
.batch(10)».fmt("%3d").join: "\n ";
say "\nCount of English cardinal anagrams up to {.&comma}: " ~
+%eca.grep(+*.value > 1)».value.map: *.flat;
say "\nLargest group(s) of English cardinal anagrams up to {.&comma}:\n [" ~
%eca.&all-max( :by(+*.value) )».value.sort.join("]\n [") ~ ']'
}
- Output:
First 30 English cardinal anagrams: 67 69 76 79 96 97 102 103 104 105 106 107 108 109 112 122 123 124 125 126 127 128 129 132 133 134 135 136 137 138 Count of English cardinal anagrams up to 1,000: 317 Largest group(s) of English cardinal anagrams up to 1,000: [679 697 769 796 967 976] Count of English cardinal anagrams up to 10,000: 2534 Largest group(s) of English cardinal anagrams up to 10,000: [1679 1697 1769 1796 1967 1976 6179 6197 6791 6971 7169 7196 7691 7961 9167 9176 9671 9761] [2679 2697 2769 2796 2967 2976 6279 6297 6792 6972 7269 7296 7692 7962 9267 9276 9672 9762] [3679 3697 3769 3796 3967 3976 6379 6397 6793 6973 7369 7396 7693 7963 9367 9376 9673 9763] [4679 4697 4769 4796 4967 4976 6479 6497 6794 6974 7469 7496 7694 7964 9467 9476 9674 9764] [5679 5697 5769 5796 5967 5976 6579 6597 6795 6975 7569 7596 7695 7965 9567 9576 9675 9765] [6798 6879 6897 6978 7698 7869 7896 7968 8679 8697 8769 8796 8967 8976 9678 9768 9867 9876]
Wren
import "./sort" for Sort
import "./fmt" for Fmt, Name
for (limit in [1000, 10000]) {
var ana = {}
for (i in 0..limit) {
var key = Sort.quick(Name.fromNum(i).toList).join("")
if (ana.containsKey(key)) {
ana[key].add(i)
} else {
ana[key] = [i]
}
}
if (limit == 1000) {
var all = []
for (v in ana.values) {
if (v.count > 1) all.addAll(v)
}
System.print("First 30 English cardinal anagrams:")
Fmt.tprint("$3d", all.sort().take(30), 10)
System.print()
}
var count = ana.count { |me| me.value.count > 1 }
Fmt.print("Count of English cardinal anagrams up to $,d: $,d", limit, count)
var max = 0
var largest
for (v in ana.values) {
if (v.count > max) {
max = v.count
largest = [v]
} else if (v.count == max) {
largest.add(v)
}
}
Fmt.print("\nLargest group(s) of English cardinal anagrams up to $,d:", limit)
largest.sort { |l1, l2| l1[0] < l2[0] }
System.print(largest.map { |l| "[" + l.join(" ") + "]" }.join("\n"))
if (limit == 1000) System.print()
}
- Output:
First 30 English cardinal anagrams: 67 69 76 79 96 97 102 103 104 105 106 107 108 109 112 122 123 124 125 126 127 128 129 132 133 134 135 136 137 138 Count of English cardinal anagrams up to 1,000: 317 Largest group(s) of English cardinal anagrams up to 1,000: [679 697 769 796 967 976] Count of English cardinal anagrams up to 10,000: 2,534 Largest group(s) of English cardinal anagrams up to 10,000: [1679 1697 1769 1796 1967 1976 6179 6197 6791 6971 7169 7196 7691 7961 9167 9176 9671 9761] [2679 2697 2769 2796 2967 2976 6279 6297 6792 6972 7269 7296 7692 7962 9267 9276 9672 9762] [3679 3697 3769 3796 3967 3976 6379 6397 6793 6973 7369 7396 7693 7963 9367 9376 9673 9763] [4679 4697 4769 4796 4967 4976 6479 6497 6794 6974 7469 7496 7694 7964 9467 9476 9674 9764] [5679 5697 5769 5796 5967 5976 6579 6597 6795 6975 7569 7596 7695 7965 9567 9576 9675 9765] [6798 6879 6897 6978 7698 7869 7896 7968 8679 8697 8769 8796 8967 8976 9678 9768 9867 9876]