Anadromes: Difference between revisions

12,585 bytes added ,  2 months ago
New post.
imported>Rowsety Moid
No edit summary
(New post.)
 
(8 intermediate revisions by 8 users not shown)
Line 81:
 
=={{header|ALGOL 68}}==
Reads the words from standard input, stopping when a word = ZZZ is found (which is the last word in words.txt).<br>
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<br>
(I haven't tried it with Linux).<br>
Line 131:
list[ low ] = item
END # contains # ;
 
# set the end of file handler for stand in #
on logical file end( stand in, ( REF FILE f )BOOL: at eof := TRUE );
 
[ 1 : 500 000 ]STRING words;
Line 137 ⟶ 140:
INT max length := 0;
BOOL at eof := FALSE;
WHILE NOT at eof
DO
STRING word;
read( ( word, newline ) );
NOT at eof := word = "ZZZ";
DO
t count +:= 1;
INT w length := 1 + ( UPB word - LWB word );
Line 175 ⟶ 178:
OD;
print( ( newline, "Found ", whole( a count, 0 ), " anadromes", newline ) )
END
END</syntaxhighlight>
</syntaxhighlight>
{{out}}
<pre>
Line 409 ⟶ 413:
(let ((rev (reverse word)))
(and (string-lessp word rev)
(gethash rev dict))))
(not (string-equal word rev)))))
words))))
 
Line 567 ⟶ 570:
{{out}}
[[File:32 Anadromes.png]]
 
=={{header|Go}}==
{{works with|go|1.21}}
<syntaxhighlight lang="go">package main
 
import (
"bufio"
"cmp"
"fmt"
"log"
"os"
"slices"
"strings"
"unicode/utf8"
)
 
func main() {
words := readUniqueWords("words.txt", 6)
anadromes := getAnadromes(words)
lefts := sortedKeys(anadromes)
for _, left := range lefts {
right := anadromes[left]
fmt.Printf("%9s ↔ %s\n", left, right)
}
}
 
func readUniqueWords(filename string, minLen int) map[string]struct{} {
file, err := os.Open(filename)
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
words := map[string]struct{}{}
for scanner.Scan() {
word := scanner.Text()
if utf8.RuneCountInString(word) > minLen {
word = strings.ToLower(word)
words[word] = struct{}{}
}
}
return words
}
 
func getAnadromes(words map[string]struct{}) map[string]string {
seen := map[string]struct{}{}
anadromes := map[string]string{}
for _, word := range sortedKeys(words) {
rword := reverse(word)
if rword != word {
if _, found := words[rword]; found {
if _, found := seen[word]; !found {
if _, found := seen[rword]; !found {
anadromes[word] = rword
seen[word] = struct{}{}
seen[rword] = struct{}{}
}
}
}
}
}
return anadromes
}
 
func sortedKeys[K cmp.Ordered, V any](m map[K]V) []K {
keys := make([]K, 0, len(m))
for key := range m {
keys = append(keys, key)
}
slices.Sort(keys)
return keys
}
 
func reverse(text string) string {
runes := []rune(text)
slices.Reverse(runes)
return string(runes)
}</syntaxhighlight>
 
{{out}}
<pre>
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
</pre>
 
=={{header|Haskell}}==
Line 674 ⟶ 791:
│sallets │stellas │
└────────┴────────┘</syntaxhighlight>
 
=={{header|Java}}==
<syntaxhighlight lang="java">
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
 
public class Anadromes {
 
public static void main(String[] args) throws IOException {
List<String> words = Files.lines(Path.of("words.txt")).filter( word -> word.length() > 6 ).sorted().toList();
System.out.println("The anadrome pairs with more than 6 letters are:");
for ( String word : words ) {
String wordReversed = new StringBuilder(word).reverse().toString();
if ( wordReversed.compareTo(word) > 0 && Collections.binarySearch(words, wordReversed) > 0 ) {
System.out.println(word + " <--> " + wordReversed);
}
}
}
 
}
</syntaxhighlight>
{{ out }}
<pre>
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
</pre>
 
=={{header|JavaScript}}==
<syntaxhighlight lang="JavaScript">
const fs = require('fs');
 
fs.readFile("words.txt", "utf8", (err, data) => {
if (err) {
console.error("Error reading the file:", err);
return;
}
 
const words = data.split(/\r?\n/); // This regex splits on both Unix and Windows line endings
const wordSet = new Set(words);
const seenWords = new Set();
const wordList = [];
 
for (let word of wordSet) {
if (word.length > 6) {
const reversedWord = word.split('').reverse().join('');
const wordPair = `${word}:${reversedWord}`;
const reversedWordPair = `${reversedWord}:${word}`;
 
if (wordSet.has(reversedWord) && reversedWord !== word && !seenWords.has(reversedWordPair)) {
wordList.push([word, reversedWord]);
seenWords.add(wordPair); // Store seen words as a string pair to make it easy to check
}
}
}
 
console.log(wordList.length);
 
wordList.sort((a, b) => a[0].localeCompare(b[0])).forEach(([word, reversedWord]) => {
console.log(`${word.padStart(9)} ${reversedWord}`);
});
});
</syntaxhighlight>
{{out}}
<pre>
17
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
</pre>
 
 
=={{header|jq}}==
Line 1,033 ⟶ 1,254:
   leper <=> repel   
   lever <=> revel   
</pre>
=={{header|Python}}==
<syntaxhighlight lang="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}")
</syntaxhighlight>
{{out}}
</pre>
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
</pre>
 
Line 1,207 ⟶ 1,465:
</pre>
 
 
=={{header|SETL}}==
<syntaxhighlight lang="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;</syntaxhighlight>
{{out}}
<pre>{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}</pre>
 
=={{header|Sidef}}==
Line 1,240 ⟶ 1,543:
dessert <=> tressed
</pre>
=={{header|Swift}}==
A complete implementation of a partitioning approach with async processing.
 
Supporting class:
<syntaxhighlight lang="swift">
import Foundation
import Algorithms
 
extension String {
var firstAndLast: String { String(self.first!) + String(self.last!) }
var backwards: String { String(self.reversed()) }
}
 
class AnadromeIndex {
 
// Stucture to index by length and the first and last character
// [ length: [ firstAndLast: [ words ] ] ]
/// Only compare words of same length, and where
/// firstAndLast corresponds to its reverse
var dict: [Int: [String: [String]]] = [:]
 
func loadFile(
fileURL: URL,
minLen: Int,
byLine: Bool = false
) async -> (Int, Int) {
var linesRead = 0
var wordsIndexed = 0
do {
if byLine {
for try await line in fileURL.lines {
linesRead += 1
if line.count < minLen { continue }
wordsIndexed += 1
self.addWord( line
.trimmingCharacters(in: .whitespacesAndNewlines)
)
}
} else {
let fileString = try String(contentsOf: fileURL, encoding: .utf8)
for line in fileString.components(separatedBy: .newlines) {
linesRead += 1
if line.count < minLen { continue }
wordsIndexed += 1
self.addWord( line
.trimmingCharacters(in: .whitespacesAndNewlines)
)
}
}
} catch {
debugPrint(error)
}
return (linesRead, wordsIndexed)
}
 
func addWord(_ str: String) {
let len = str.count
let index = str.firstAndLast
if let azDict = dict[len] {
if azDict[index] != nil {
self.dict[len]![index]!.append(str)
} else {
self.dict[len]!.updateValue([str], forKey: index)
}
} else {
dict.updateValue([index: [str]], forKey: len)
}
}
 
func findAnadromes() async -> [String] {
var done: [String] = []
var results: [String] = []
let allResults = await withTaskGroup(
of: [String].self,
returning: [String].self) { group in
// By length
for len in self.dict.keys.sorted() {
if let lenSet = self.dict[len] {
// By firstAndLast characters
for az in lenSet.keys.sorted() {
let za = az.backwards
if done.contains(where: { $0 == "\(len)\(az)" || $0 == "\(len)\(za)" })
|| lenSet[za] == nil { continue }
done += ["\(len)\(az)", "\(len)\(za)"]
group.addTask {
let lh = lenSet[az]!
let rh = lenSet[za]!
let f = await self.searchProduct(lh: lh, rh: rh)
return f
}
}
}
}
for await result in group {
results += result
}
return results
}
return allResults
}
 
func searchProduct(lh: [String], rh: [String]) async -> [String] {
var found: [String] = []
for ( s1, s2 ) in product(lh, rh) {
if s1 == s2 { continue } // palindrome
if s1 == String(s2.reversed())
&& !found.contains(where: {$0 == s2 || $0 == s1}) {
found.append(s1)
}
}
return found
}
}
</syntaxhighlight>
Usage:
<syntaxhighlight lang="swift">
import Foundation
import ArgumentParser
 
@main
struct AnadromeFinder: AsyncParsableCommand {
@Argument(help: "File containing words", transform: URL.init(fileURLWithPath:))
var file: URL
 
@Option(name: .shortAndLong)
var minLen: Int = 6
 
@Flag(name: .shortAndLong)
var verbose = false
 
mutating func run() async throws {
let indexSet = AnadromeIndex()
var start = Date()
let (lines, words) = await indexSet.loadFile(fileURL: file, minLen: minLen)
if verbose {
printStderr("\(lines.formatted()) lines read,",
"\(words.formatted()) hashed in",
"\(since(start).formatted()) sec")
}
start = Date()
let found = await indexSet.findAnadromes()
if verbose {
printStderr("\(found.count.formatted()) matches found in",
"\(since(start)) seconds")
}
// Print results
for e in found.sorted(by: {a, b in
if a.count == b.count { return a < b }
return a.count < b.count
}) {
print(e, e.backwards)
}
}
func since(_ dt: Date) -> TimeInterval {
return Date().timeIntervalSince(dt)
}
func printStderr(
_ items: Any...,
separator: String = " ",
terminator: String = "\n"
) {
let output = items
.map { String(describing: $0) }
.joined(separator: separator) + terminator
FileHandle.standardError.write(output.data(using: .utf8)!)
}
}
</syntaxhighlight>
Output:
<syntaxhighlight lang="sh">
% ./Anadromes --verbose /Users/username/Downloads/words.txt
466,551 lines read, 427,054 hashed in 5.52172 sec
83 matches found in 7.691561937332153 seconds
abrood doorba
agenes senega
amunam manuma
animal lamina
animes semina
bruted deturb
darter retrad
decart traced
decurt truced
deflow wolfed
degami imaged
denier reined
denies seined
depots stoped
derats stared
dessus sussed
dewans snawed
dialer relaid
diaper repaid
dibrom morbid
dorter retrod
drawer reward
elides sedile
elutes setule
enserf fresne
ergate etagre
eviler relive
gangan nagnag
gawgaw wagwag
golfer reflog
hallan nallah
lemmas sammel
lesson nossel
liever reveil
looter retool
manitu utinam
mooder redoom
nedder redden
pupils slipup
rebuts stuber
recaps spacer
recart tracer
redips spider
reflow wolfer
reives sevier
reknit tinker
remeet teemer
repins sniper
report troper
repots stoper
retros sorter
scares seracs
secret terces
selahs shales
serves sevres
sinnet tennis
skeets steeks
sleeps speels
sleets steels
sloops spools
snoops spoons
spirts strips
sports strops
sprits stirps
struts sturts
territ tirret
amaroid diorama
degener reneged
deifier reified
deliver reviled
dessert tressed
deviler relived
gateman nametag
leveler relevel
pat-pat tap-tap
reknits stinker
relever reveler
reliver reviler
revotes setover
sallets stellas
desserts stressed
dioramas samaroid
redrawer rewarder
</syntaxhighlight>
 
=={{header|Wren}}==
{{libheader|Wren-sort}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="ecmascriptwren">import "io" for File
import "./sort" for Sort, Find
import "./fmt" for Fmt
871

edits