Anadromes

You are encouraged to solve this task according to the task description, using any language you may know.
An anadrome is similar to a palindrome except, rather than spelling the same word or phrase when reversed, it spells a different word or phrase. An anadrome is a special case of an anagram.
Anadrome is a portmanteau of the words anagram and palindrome.
For instance, regal and lager are anadromes.
- Task
Using the words.txt file from https://github.com/dwyl/english-words, find and display all of the anadrome pairs with more than 6 characters.
Each word pair should only show up one time in the list.
Ada
-- Find all anadromes of length > 6
-- J. Carter 2023 Mar
with Ada.Containers.Indefinite_Ordered_Sets;
with Ada.Text_IO;
procedure Anadromes is
package Word_Sets is new Ada.Containers.Indefinite_Ordered_Sets (Element_Type => String);
function Reversed (S : in String) return String is
(if S = "" then S else S (S'Last) & Reversed (S (S'First .. S'Last - 1) ) );
File : Ada.Text_IO.File_Type;
W : Word_Sets.Set;
begin -- Anadromes
Ada.Text_IO.Open (File => File, Mode => Ada.Text_IO.In_File, Name => "words.txt");
Fill : loop
exit Fill when Ada.Text_IO.End_Of_File (File);
W.Insert (New_Item => Ada.Text_IO.Get_Line (File) );
end loop Fill;
Ada.Text_IO.Close (File => File);
Search : for Word of W loop
if Word'Length > 6 then
Backwards : declare
Rev : constant String := Reversed (Word);
begin -- Backwards
if Word < Rev and W.Contains (Rev) then
Ada.Text_IO.Put_Line (Item => Word & (1 .. 10 - Word'Length => ' ') & Rev);
end if;
end Backwards;
end if;
end loop Search;
end Anadromes;
- Output:
amaroid diorama degener reneged deifier reified deliver reviled dessert tressed desserts stressed deviler relived dioramas samaroid gateman nametag leveler relevel pat-pat tap-tap redrawer rewarder reknits stinker relever reveler reliver reviler revotes setover sallets stellas
ALGOL 68
Reads the words from standard input, stopping when a word = ZZZ is found (which is the last word in words.txt).
Unfortunately, Algol 68G doesn't like an array of STRINGs with more than 300 000 elements, even though it allows INT arrays to have millions - at least under Windows
(I haven't tried it with Linux).
So you will need to use another compiler under Windows.
As in the Wren sample, the words are quicksorted so binary searching can be used to find the reversed words.
BEGIN # find some anadromes: words that whwn reversed are also words #
# in-place quick sort an array of strings #
PROC s quicksort = ( REF[]STRING a, INT lb, ub )VOID:
IF ub > lb
THEN
# more than one element, so must sort #
INT left := lb;
INT right := ub;
# choosing the middle element of the array as the pivot #
STRING pivot := a[ left + ( ( right + 1 ) - left ) OVER 2 ];
WHILE
WHILE IF left <= ub THEN a[ left ] < pivot ELSE FALSE FI
DO
left +:= 1
OD;
WHILE IF right >= lb THEN a[ right ] > pivot ELSE FALSE FI
DO
right -:= 1
OD;
left <= right
DO
STRING t := a[ left ];
a[ left ] := a[ right ];
a[ right ] := t;
left +:= 1;
right -:= 1
OD;
s quicksort( a, lb, right );
s quicksort( a, left, ub )
FI # s quicksort # ;
# returns TRUE if item is in list, FALSE otherwise #
# - based on the iterative routine in the binary search task #
PROC contains = ( []STRING list, STRING item, INT lb, ub )BOOL:
BEGIN
INT low := lb,
INT high := ub;
WHILE low < high DO
INT mid = ( low + high ) OVER 2;
IF list[ mid ] > item THEN high := mid - 1
ELIF list[ mid ] < item THEN low := mid + 1
ELSE low := high := mid
FI
OD;
list[ low ] = item
END # contains # ;
[ 1 : 500 000 ]STRING words;
INT t count := 0;
INT w count := 0;
INT max length := 0;
BOOL at eof := FALSE;
WHILE NOT at eof
DO
STRING word;
read( ( word, newline ) );
at eof := word = "ZZZ";
t count +:= 1;
INT w length := 1 + ( UPB word - LWB word );
IF w length > 6 THEN
w count +:= 1;
words[ w count ] := word;
IF w length > max length THEN max length := w length FI
FI
OD;
print( ( "read ", whole( t count, 0 ), " words, "
, "the longest is ", whole( max length, 0 ), " characters"
, newline
, " ", whole( w count, 0 ), " words are longer than 6 characters"
, newline, newline
)
);
s quicksort( words, 1, w count ); # sort the words for binary search #
print( ( "The following anadromes are present:", newline, newline ) );
INT a count := 0;
FOR i TO w count DO
STRING word = words[ i ];
STRING reverse word := "";
FOR w pos FROM LWB word TO UPB word DO word[ w pos ] +=: reverse word OD;
IF word < reverse word THEN
IF contains( words, reverse word, 1, w count ) THEN
# have an anadromic pair #
INT w length = 1 + ( UPB words[ i ] - LWB words[ i ] );
FOR c TO 10 - w length DO print( ( " " ) ) OD;
print( ( words[ i ], " :: ", reverse word, newline ) );
a count +:= 1
FI
FI
OD;
print( ( newline, "Found ", whole( a count, 0 ), " anadromes", newline ) )
END
- Output:
read 466551 words, the longest is 45 characters 387537 words are longer than 6 characters The following anadromes are present: amaroid :: diorama degener :: reneged deifier :: reified deliver :: reviled dessert :: tressed desserts :: stressed deviler :: relived dioramas :: samaroid gateman :: nametag leveler :: relevel pat-pat :: tap-tap redrawer :: rewarder reknits :: stinker relever :: reveler reliver :: reviler revotes :: setover sallets :: stellas Found 17 anadromes
AppleScript
use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"
use scripting additions
on Anadromes(textFile, minLength)
set |⌘| to current application
-- Read the text from the file.
set theText to |⌘|'s class "NSString"'s stringWithContentsOfFile:(textFile's POSIX path) ¬
usedEncoding:(missing value) |error|:(missing value)
-- Lose paragraphs (one word per paragraph) which have fewer than minLength characters.
set theText to theText's stringByReplacingOccurrencesOfString:("(?m)^.{0," & minLength - 1 & "}\\R") withString:("") ¬
options:(|⌘|'s NSRegularExpressionSearch) range:({0, theText's |length|()})
-- Get the remaining paragraphs as an array.
set wordArray to (theText's componentsSeparatedByCharactersInSet:(|⌘|'s class "NSCharacterSet"'s controlCharacterSet()))
-- Derive a list of reversed words.
script o
property wordList : (wordArray) as list
end script
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to ""
repeat with i from 1 to (count o's wordList)
set o's wordList's item i to (o's wordList's item i's characters's reverse) as text
end repeat
-- Get a list of words that are in both the original and reversed groups.
set reversedWordSet to |⌘|'s class "NSSet"'s setWithArray:(o's wordList)
set filter to |⌘|'s class "NSPredicate"'s predicateWithFormat_("self IN %@", reversedWordSet)
set o's wordList to (wordArray's filteredArrayUsingPredicate:(filter)) as list
-- Build the output line by line, omitting palindromes and already matched word pairs.
set output to {}
repeat with i from 1 to (count o's wordList)
set thisWord to o's wordList's item i
set o's wordList's item i to missing value
set reversedWord to (thisWord's characters's reverse) as text
if ({reversedWord} is in o's wordList) then set output's end to thisWord & " <--> " & reversedWord
end repeat
set AppleScript's text item delimiters to linefeed
set output to output as text
set AppleScript's text item delimiters to astid
return output
end Anadromes
return Anadromes(((path to desktop as text) & "www.rosettacode.org:words.txt") as «class furl», 7)
- Output:
"amaroid <--> diorama
degener <--> reneged
deifier <--> reified
deliver <--> reviled
dessert <--> tressed
desserts <--> stressed
deviler <--> relived
dioramas <--> samaroid
gateman <--> nametag
leveler <--> relevel
pat-pat <--> tap-tap
redrawer <--> rewarder
reknits <--> stinker
relever <--> reveler
reliver <--> reviler
revotes <--> setover
sallets <--> stellas"
AWK
# syntax: GAWK -f ANADROMES.AWK WORDS.TXT
#
# sorting:
# PROCINFO["sorted_in"] is used by GAWK
# SORTTYPE is used by Thompson Automation's TAWK
#
BEGIN {
width = 6
}
{ if (length($0) > width) {
arr[$0]++
}
}
END {
PROCINFO["sorted_in"] = "@ind_str_asc" ; SORTTYPE = 1
for (i in arr) {
tmp = reverse(i)
if (tmp in arr) {
if (i == tmp) { continue }
if (tmp in shown_arr) { continue }
printf("%11s %11s\n",i,tmp)
shown_arr[i] = ""
}
}
printf("%d words, %d > %d characters, %d anadromes\n",NR,length(arr),width,length(shown_arr))
exit(0)
}
function reverse(str, i,rts) {
for (i=length(str); i>=1; i--) {
rts = rts substr(str,i,1)
}
return(rts)
}
- Output:
amaroid diorama degener reneged deifier reified deliver reviled dessert tressed desserts stressed deviler relived dioramas samaroid gateman nametag leveler relevel pat-pat tap-tap redrawer rewarder reknits stinker relever reveler reliver reviler revotes setover sallets stellas 466551 words, 387537 > 6 characters, 17 anadromes
C++
#include <algorithm>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> words;
std::ifstream in("words.txt");
if (!in) {
std::cerr << "Cannot open file words.txt.\n";
return EXIT_FAILURE;
}
std::string line;
while (getline(in, line)) {
if (line.size() > 6)
words.push_back(line);
}
sort(words.begin(), words.end());
for (const std::string& word : words) {
std::string reversed(word.rbegin(), word.rend());
if (reversed > word &&
binary_search(words.begin(), words.end(), reversed)) {
std::cout << std::setw(8) << word << " <-> " << reversed << '\n';
}
}
return EXIT_SUCCESS;
}
- Output:
amaroid <-> diorama degener <-> reneged deifier <-> reified deliver <-> reviled dessert <-> tressed desserts <-> stressed deviler <-> relived dioramas <-> samaroid gateman <-> nametag leveler <-> relevel pat-pat <-> tap-tap redrawer <-> rewarder reknits <-> stinker relever <-> reveler reliver <-> reviler revotes <-> setover sallets <-> stellas
Common Lisp
The hash-table's equalp
test is case-insensitive, and so we find 32 pairs rather than 17. However, the table maps each word to itself, and so looking up a reversed word gets it in its original case, as can be seen in the output.
(defun read-words (filename)
(let ((words '()))
(with-open-file (s filename :direction :input)
(loop
(let ((word (read-line s nil nil)))
(if word
(when (> (length word) 6)
(setq words (cons word words)))
(return (reverse words))))))))
(defun anadromes ()
(let ((words (read-words "notes/words.txt"))
(dict (make-hash-table :test #'equalp)))
(dolist (word words)
(setf (gethash word dict) word))
(mapcar
(lambda (word)
(list word (gethash (reverse word) dict)))
(remove-if-not
(lambda (word)
(let ((rev (reverse word)))
(and (string-lessp word rev)
(gethash rev dict))))
words))))
(format t "~%~:{~10A ~10A~%~}~%"
(anadromes))
- Output:
amaroid diorama anacara Aracana Annabal Labanna Artamus Sumatra Colbert Trebloc degener reneged deifier reified Delbert trebled Delevan naveled deliver reviled dessert tressed desserts stressed deviler relived dioramas samaroid Eimmart trammie Emmeram maremme gateman nametag Latimer remital Lattimer remittal lessees Seessel leveler relevel Nicolaus Sualocin pat-pat tap-tap redrawer rewarder reknits stinker relever reveler reliver reviler revotes setover ROYGBIV vibgyor Rotanev Venator sallets stellas sennits Stinnes
F#
// Anadromes. Nigel Galloway: June 26th., 2022
let words=seq{use n=System.IO.File.OpenText("words.txt") in while not n.EndOfStream do yield n.ReadLine()}|>Seq.filter(fun n->6<(Seq.length n))|>Seq.map(fun n->n.ToCharArray())|>Set.ofSeq
Set.intersect words (words|>Set.map(Array.rev))|>Set.iter(fun n->if n<Array.rev n then printfn "%s" (System.String n))
- Output:
amaroid degener deifier deliver dessert desserts deviler dioramas gateman leveler pat-pat redrawer reknits relever reliver revotes sallets
Factor
USING: assocs grouping hash-sets io.encodings.ascii io.files
kernel math prettyprint sequences sets sets.extras ;
"words.txt" ascii file-lines [ length 6 > ] filter dup >hash-set '[ reverse _ in? ] filter
[ reverse ] zip-with [ all-equal? ] reject [ fast-set ] unique-by .
- Output:
{ { "amaroid" "diorama" } { "degener" "reneged" } { "deifier" "reified" } { "deliver" "reviled" } { "dessert" "tressed" } { "desserts" "stressed" } { "deviler" "relived" } { "dioramas" "samaroid" } { "gateman" "nametag" } { "leveler" "relevel" } { "pat-pat" "tap-tap" } { "redrawer" "rewarder" } { "reknits" "stinker" } { "relever" "reveler" } { "reliver" "reviler" } { "revotes" "setover" } { "sallets" "stellas" } }
FutureBasic
begin globals
ptr gwordsPtr
uint32 gfilen
end globals
local fn loadDict
window 1, @"Anadromes",(0,0,209,502)
CFURLRef url = fn URLWithString( @"file:///Applications/FutureBasic/words.txt" )
if ( url )
open "I", 1, url
gfilen = lof( 1 )
gwordsPtr = fn malloc( gfilen )
read file 1, gwordsPtr, gfilen
close
end if
end fn
local fn anadromes
uint32 r, i, top, bot, med, count = 0
CFStringRef string = lcase(fn StringWithBytes( gwordsPtr, gfilen, NSASCIIStringEncoding ))
CFArrayRef array = fn StringComponentsSeparatedByString( string, @"\n" )
: array = fn arraySortedarrayUsingSelector( array, @"caseInsensitiveCompare:" )
print
for r = 0 to len(array)-1
if len( array[r] ) < 7 then continue
string = @""
for i = 0 to len(array[r]) - 1
string = fn StringByAppendingString( mid( array[r],i,1 ), string )
next
if fn StringIsEqual( array[r], string ) then continue
bot = r+1 : top = len( array )-1
while ( top - bot ) > 1
med = ( bot + top )>>1
select fn StringCompare( string, array[med] )
case NSOrderedAscending : top = med
case NSOrderedDescending : bot = med
case else : count++
print ,count,array[r];left( @" ",9-len(string) );string
break
end select
wend
next
end fn
fn loadDict
CFTimeInterval t = fn CACurrentMediaTime
fn anadromes
printf @"\t\t%.3f secs",fn CACurrentMediaTime - t
handleevents
- Output:
Haskell
import qualified Data.Set as S
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
-- The anadromes of a list of words. We convert all words to lower case.
anadromes :: [T.Text] -> [(T.Text, T.Text)]
anadromes ws = let set = S.fromList $ map T.toLower ws
in S.foldr (step set) [] set
where step set w ps = let rev = T.reverse w
in if w < rev && S.member rev set
then (w, rev) : ps
else ps
main :: IO ()
main = TIO.interact (T.unlines . map anaShow . anadromes . longEnough . T.lines)
where longEnough = filter ((> 6) . T.length)
anaShow (x, y) = T.unwords [x, y]
- Output:
amaroid diorama anacara aracana annabal labanna artamus sumatra colbert trebloc degener reneged deifier reified delbert trebled delevan naveled deliver reviled dessert tressed desserts stressed deviler relived dioramas samaroid eimmart trammie emmeram maremme gateman nametag latimer remital lattimer remittal lessees seessel leveler relevel nicolaus sualocin pat-pat tap-tap redrawer rewarder reknits stinker relever reveler reliver reviler revotes setover rotanev venator roygbiv vibgyor sallets stellas sennits stinnes
J
Inspecting other entries here, it seems clear that we cannot ignore case. Otherwise, 'trebled' would be an anadrome.
Anyways, the basic approach here is to identify a canonical key for each word, look for paired keys and organize the words based on those keys:
words=: cutLF fread 'words.txt'
canon=: {.@/:~@(,:|.) each words
akeys=: (~. #~ 2 = #/.~) canon
tkeys=: (#~ 6 < #@>) akeys
order=: /: canon
pairs=: _2]\ (order{canon e. tkeys) # order { words
This gives us:
pairs
┌────────┬────────┐
│amaroid │diorama │
├────────┼────────┤
│degener │reneged │
├────────┼────────┤
│deifier │reified │
├────────┼────────┤
│deliver │reviled │
├────────┼────────┤
│dessert │tressed │
├────────┼────────┤
│desserts│stressed│
├────────┼────────┤
│deviler │relived │
├────────┼────────┤
│dioramas│samaroid│
├────────┼────────┤
│gateman │nametag │
├────────┼────────┤
│leveler │relevel │
├────────┼────────┤
│pat-pat │tap-tap │
├────────┼────────┤
│redrawer│rewarder│
├────────┼────────┤
│reknits │stinker │
├────────┼────────┤
│relever │reveler │
├────────┼────────┤
│reliver │reviler │
├────────┼────────┤
│revotes │setover │
├────────┼────────┤
│sallets │stellas │
└────────┴────────┘
jq
Constructing a very large dictionary (i.e. JSON object) would be time-consuming and would require quite a lot of memory, so this implementation takes advantage of jq's `bsearch` for binary search. It also confines the search to "words" that begin with a lower-case letter. The result is the same listing of 17 words as found elsewhere on this page.
< words.txt jq -nrR ' def rev: explode | reverse | implode; ([inputs | select(length > 6 and (.[:1] | . >= "a" and . <= "z" and . <= .[-1:] )) ] | sort) as $words | $words[] | rev as $reverse | select(. < $reverse and ($words | bsearch($reverse) > -1)) | . + " <=> " + $reverse '
Julia
function anadromes(minsize, csense = true, fname = "words.txt")
words = Set(filter(w -> length(w) >= minsize, split((csense ? identity : lowercase)(read(fname, String)), r"\s+")))
found = [(w, reverse(w)) for w in words if (r = reverse(w)) in words && w < r]
println("Total $(length(found)) case $(csense ? "" : in)sensitive anadrome pairs found.")
foreach(a -> println(a[1], " <=> ", a[2]), sort!(found))
end
anadromes(7)
anadromes(7, false)
- Output:
Total 17 case sensitive anadrome pairs found. amaroid <=> diorama degener <=> reneged deifier <=> reified deliver <=> reviled dessert <=> tressed desserts <=> stressed deviler <=> relived dioramas <=> samaroid gateman <=> nametag leveler <=> relevel pat-pat <=> tap-tap redrawer <=> rewarder reknits <=> stinker relever <=> reveler reliver <=> reviler revotes <=> setover sallets <=> stellas Total 32 case insensitive anadrome pairs found. amaroid <=> diorama anacara <=> aracana annabal <=> labanna artamus <=> sumatra colbert <=> trebloc degener <=> reneged deifier <=> reified delbert <=> trebled delevan <=> naveled deliver <=> reviled dessert <=> tressed desserts <=> stressed deviler <=> relived dioramas <=> samaroid eimmart <=> trammie emmeram <=> maremme gateman <=> nametag latimer <=> remital lattimer <=> remittal lessees <=> seessel leveler <=> relevel nicolaus <=> sualocin pat-pat <=> tap-tap redrawer <=> rewarder reknits <=> stinker relever <=> reveler reliver <=> reviler revotes <=> setover rotanev <=> venator roygbiv <=> vibgyor sallets <=> stellas sennits <=> stinnes
MiniScript
This implementation is for use with the Mini Micro version of MiniScript. The command-line version does not include a HTTP library. Modify the declaration of wordList object to use the file class instead of the http class.
getPairs = function(words)
pairs = []
for i in range(0, words.len - 2)
for j in range(i + 1, words.len - 1)
pairs.push([words[i], words[j]])
end for
end for
return pairs
end function
isReversed = function(word1, word2)
for i in range(0, word1.len - 1)
if word1[i] != word2[-(i+1)] then return false
end for
return true
end function
makeKey = function(word)
return word.split("").sort.join("")
end function
wordList = http.get("https://raw.githubusercontent.com/dwyl/english-words/master/words.txt").split(char(10))
wordSets = {}
for word in wordList
k = makeKey(word)
if not wordSets.hasIndex(k) then
wordSets[k] = [word]
else
wordSets[k].push(word)
end if
end for
anadromes = []
for wordSet in wordSets.values
if wordSet.len > 1 and wordSet[0].len > 6 then
pairs = getPairs(wordSet)
for pair in pairs
if isReversed(pair[0], pair[1]) then print pair
end for
end if
end for
- Output:
["amaroid", "diorama"] ["degener", "reneged"] ["deifier", "reified"] ["deliver", "reviled"] ["deviler", "relived"] ["dessert", "tressed"] ["desserts", "stressed"] ["dioramas", "samaroid"] ["gateman", "nametag"] ["leveler", "relevel"] ["relever", "reveler"] ["revotes", "setover"] ["pat-pat", "tap-tap"] ["redrawer", "rewarder"] ["reknits", "stinker"] ["reliver", "reviler"] ["sallets", "stellas"]
Nim
import std/[sets, strutils]
func reversed(s: string): string =
## Return the reverse of a string.
## Works only for ASCII strings.
result.setLen(s.len)
for i in 1..s.len:
result[i - 1] = s[^i]
var wordSet: OrderedSet[string]
for word in lines("words.txt"):
if word.len > 6:
wordSet.incl word
for word in wordSet:
let rev = reversed(word)
if rev > word and rev in wordSet:
echo word.alignLeft(12), rev
- Output:
amaroid diorama degener reneged deifier reified deliver reviled dessert tressed desserts stressed deviler relived dioramas samaroid gateman nametag leveler relevel pat-pat tap-tap redrawer rewarder reknits stinker relever reveler reliver reviler revotes setover sallets stellas
OCaml
module StrSet = Set.Make(String)
let read_line_seq ch =
let rec repeat () =
match input_line ch with
| s -> Seq.Cons (s, repeat)
| exception End_of_file -> Nil
in repeat
let string_rev s =
let last = pred (String.length s) in
String.init (succ last) (fun i -> s.[last - i])
let get_anadromes set =
let aux s =
let r = string_rev s in
if s < r && StrSet.mem r set
then Some (s, r)
else None
in
Seq.filter_map aux (StrSet.to_seq set)
let () = read_line_seq stdin |> Seq.filter (fun s -> String.length s > 6)
|> Seq.map String.lowercase_ascii |> StrSet.of_seq |> get_anadromes
|> Seq.iter (fun (s, r) -> Printf.printf "%9s | %s\n" s r)
- Output:
amaroid | diorama anacara | aracana annabal | labanna artamus | sumatra colbert | trebloc degener | reneged deifier | reified delbert | trebled delevan | naveled deliver | reviled dessert | tressed desserts | stressed deviler | relived dioramas | samaroid eimmart | trammie emmeram | maremme gateman | nametag latimer | remital lattimer | remittal lessees | seessel leveler | relevel nicolaus | sualocin pat-pat | tap-tap redrawer | rewarder reknits | stinker relever | reveler reliver | reviler revotes | setover rotanev | venator roygbiv | vibgyor sallets | stellas sennits | stinnes
PascalABC.NET
// Anadromes. Nigel Galloway: August 30th., 2022
begin
var n := ReadLines('words.txt').Where(n -> Length(n) > 6);
foreach var v in n.Intersect(n.Select(n -> ReverseString(n))) do if v < ReverseString(v) then writeln(v);
end.
- Output:
amaroid degener deifier deliver dessert desserts deviler dioramas gateman leveler pat-pat redrawer reknits relever reliver revotes sallets
Perl
use strict;
use warnings;
my(%W,%A);
for my $w ( grep { /[A-z\-]{7,}/ } split "\n", do { local( @ARGV, $/ ) = ( 'words.txt' ); <> } ) {
my $r = reverse $w;
if ($W{$r}) { $A{$r} = sprintf "%10s ↔ %s\n", $r, $w }
else { $W{$w} = $w }
}
print $A{$_} for sort keys %A;
- Output:
amaroid ↔ diorama degener ↔ reneged deifier ↔ reified deliver ↔ reviled dessert ↔ tressed desserts ↔ stressed deviler ↔ relived dioramas ↔ samaroid gateman ↔ nametag leveler ↔ relevel pat-pat ↔ tap-tap redrawer ↔ rewarder reknits ↔ stinker relever ↔ reveler reliver ↔ reviler revotes ↔ setover sallets ↔ stellas
Phix
with javascript_semantics integer m = iff(platform()=JS?5:7) sequence words = unique(unix_dict(m,`words.txt`)) function anadrome(string w) return w<reverse(w) and binary_search(reverse(w),words)>0 end function sequence r = sort(filter(words,anadrome)), s = columnize({r,apply(r,reverse)}), t = join(s,"\n",fmt:="%8s <=> %-8s") printf(1,"Found %d anadromes:\n%s\n",{length(r),t})
- Output:
On the desktop:
Found 17 anadromes: amaroid <=> diorama degener <=> reneged deifier <=> reified deliver <=> reviled dessert <=> tressed desserts <=> stressed deviler <=> relived dioramas <=> samaroid gateman <=> nametag leveler <=> relevel pat-pat <=> tap-tap redrawer <=> rewarder reknits <=> stinker relever <=> reveler reliver <=> reviler revotes <=> setover sallets <=> stellas
Under p2js, aka in a browser, from where it cannot realistically read disk files, unix_dict() ignores the filename parameter and uses the smaller unixdict.txt, as by now quite some time ago converted into a dirty great big Phix sequence constant and then transpiled into a JavaScript Array, for which we also drop the minimum length to 5, and get:
Found 5 anadromes: damon <=> nomad kramer <=> remark lager <=> regal leper <=> repel lever <=> revel
Python
# anadrome.py by Xing216
with open("words.txt","r") as f:
words = f.read().splitlines()
word_set = set(words)
seen_words = []
word_list = []
for word in word_set:
if len(word) > 6:
reversed_word = word[::-1]
if reversed_word in word_set and reversed_word != word \
and (reversed_word,word) not in seen_words:
word_list.append((word, reversed_word))
seen_words.append((word,reversed_word))
for word,reversed_word in sorted(word_list, key=lambda x: x[0]):
print(f"{word:>9} {reversed_word}")
- Output:
amaroid diorama deifier reified desserts stressed dioramas samaroid leveler relevel nametag gateman redrawer rewarder reknits stinker relived deviler reneged degener reveler relever reviled deliver reviler reliver setover revotes stellas sallets tap-tap pat-pat tressed dessert
Raku
my @words = 'words.txt'.IO.slurp.words.grep: *.chars > 6;
my %words = @words.pairs.invert;
put join "\n", @words.map: { %words{$_}:delete and sprintf "%10s ↔ %s", $_, .flip if ($_ ne .flip) && %words{.flip} }
- Output:
amaroid ↔ diorama degener ↔ reneged deifier ↔ reified deliver ↔ reviled dessert ↔ tressed desserts ↔ stressed deviler ↔ relived dioramas ↔ samaroid gateman ↔ nametag leveler ↔ relevel pat-pat ↔ tap-tap redrawer ↔ rewarder reknits ↔ stinker relever ↔ reveler reliver ↔ reviler revotes ↔ setover sallets ↔ stellas
Ruby
words = File.readlines("words.txt", chomp: true).reject{|word| word.size <= 6}
reversed_words = words.map(&:reverse)
reversables = (words & reversed_words).reject{|word| word == word.reverse}
res = reversables.uniq{|w| [w, w.reverse].sort}
res.each{|w| puts "#{w} - #{w.reverse}".center(20) }
- Output:
amaroid - diorama degener - reneged deifier - reified deliver - reviled dessert - tressed desserts - stressed deviler - relived dioramas - samaroid gateman - nametag leveler - relevel pat-pat - tap-tap redrawer - rewarder reknits - stinker relever - reveler reliver - reviler revotes - setover sallets - stellas
Rust
use std::collections::BTreeSet;
use std::fs::File;
use std::io::{self, BufRead};
fn load_dictionary(filename: &str, min_length: usize) -> std::io::Result<BTreeSet<String>> {
let file = File::open(filename)?;
let mut dict = BTreeSet::new();
for line in io::BufReader::new(file).lines() {
let word = line?;
if word.len() >= min_length {
dict.insert(word);
}
}
Ok(dict)
}
fn main() {
match load_dictionary("words.txt", 7) {
Ok(dictionary) => {
for word in &dictionary {
let rev = String::from_iter(word.chars().rev());
if rev > *word && dictionary.contains(&rev) {
println!("{:<8} <-> {}", word, rev);
}
}
}
Err(error) => eprintln!("{}", error),
}
}
- Output:
amaroid <-> diorama degener <-> reneged deifier <-> reified deliver <-> reviled dessert <-> tressed desserts <-> stressed deviler <-> relived dioramas <-> samaroid gateman <-> nametag leveler <-> relevel pat-pat <-> tap-tap redrawer <-> rewarder reknits <-> stinker relever <-> reveler reliver <-> reviler revotes <-> setover sallets <-> stellas
Seed7
$ include "seed7_05.s7i";
const func boolean: binarySearch (in array string: haystack, in string: needle) is func
result
var boolean: result is FALSE;
local
var integer: low is 1;
var integer: high is -1;
var integer: middle is -1;
begin
high := length(haystack);
while result = FALSE and low <= high do
middle := low + (high - low) div 2;
if needle < haystack[middle] then
high := pred(middle);
elsif needle > haystack[middle] then
low := succ(middle);
else
result := TRUE;
end if;
end while;
end func;
const proc: main is func
local
var file: dictionary is STD_NULL;
var string: word is "";
var string: reversed is "";
var array string: words is (array string).value;
begin
dictionary := open("words.txt", "r");
while not eof(dictionary) do
readln(dictionary, word);
words &:= word;
end while;
close(dictionary);
words := sort(words);
for word range words do
reversed := reverse(word);
if length(word) > 6 and word < reversed and binarySearch(words, reversed) then
writeln(word <& " <-> " <& reversed);
end if;
end for;
end func;
- Output:
amaroid <-> diorama degener <-> reneged deifier <-> reified deliver <-> reviled dessert <-> tressed desserts <-> stressed deviler <-> relived dioramas <-> samaroid gateman <-> nametag leveler <-> relevel pat-pat <-> tap-tap redrawer <-> rewarder reknits <-> stinker relever <-> reveler reliver <-> reviler revotes <-> setover sallets <-> stellas
SETL
program find_anadromes;
read_file;
anadromes := {
{word, reverse word}
: word in words
| reverse word in words
and reverse word /= word
};
loop for anadrome in anadromes do
print(anadrome);
end loop;
read_file::
words := {};
dictfile := open("words.txt", "r");
loop doing
geta(dictfile, word);
while word /= om do
if #word <= 6 then continue; end if;
words with:= word;
end loop;
close(dictfile);
end program;
- Output:
{amaroid diorama} {degener reneged} {deifier reified} {deliver reviled} {dessert tressed} {desserts stressed} {deviler relived} {dioramas samaroid} {gateman nametag} {leveler relevel} {'pat-pat' 'tap-tap'} {redrawer rewarder} {reknits stinker} {relever reveler} {reliver reviler} {revotes setover} {sallets stellas}
Sidef
var S = Hash()
File('words.txt').open_r.each {|word|
word.len > 6 || next
if (S.has(word.flip)) {
say "#{word.flip} <=> #{word}"
}
else {
S{word} = true
}
}
- Output:
amaroid <=> diorama gateman <=> nametag deifier <=> reified leveler <=> relevel deviler <=> relived degener <=> reneged relever <=> reveler deliver <=> reviled reliver <=> reviler redrawer <=> rewarder dioramas <=> samaroid revotes <=> setover sallets <=> stellas reknits <=> stinker desserts <=> stressed pat-pat <=> tap-tap dessert <=> tressed
Wren
import "io" for File
import "./sort" for Sort, Find
import "./fmt" for Fmt
var wordList = "words.txt" // local copy
var words = File.read(wordList)
.trimEnd()
.split("\n")
.where { |word| word.count > 6 }
.toList
Sort.quick(words) // need strict lexicographical order to use binary search
var anadromes = []
for (word in words) {
var word2 = word[-1..0]
if (word != word2 && !anadromes.contains(word2) && Find.first(words, word2) >= 0) {
anadromes.add(word)
}
}
System.print("The anadrome pairs with more than 6 letters are:")
for (ana in anadromes) Fmt.print("$8s <-> $8s", ana, ana[-1..0])
- Output:
The anadrome pairs with more than 6 letters are: amaroid <-> diorama degener <-> reneged deifier <-> reified deliver <-> reviled dessert <-> tressed desserts <-> stressed deviler <-> relived dioramas <-> samaroid gateman <-> nametag leveler <-> relevel pat-pat <-> tap-tap redrawer <-> rewarder reknits <-> stinker relever <-> reveler reliver <-> reviler revotes <-> setover sallets <-> stellas