Last letter-first letter: Difference between revisions
Content deleted Content added
→{{header|Rust}}: No need to construct the full example string until the very end. |
Thundergnat (talk | contribs) Rename Perl 6 -> Raku, alphabetize, minor clean-up |
||
Line 914: | Line 914: | ||
323: voltorb breloom mandibuzz zekr... |
323: voltorb breloom mandibuzz zekr... |
||
longest found: 323</lang> |
longest found: 323</lang> |
||
=={{header|Clojure}}== |
|||
<lang clojure>(ns rosetta-code.last-letter-first-letter |
|||
(:require clojure.string)) |
|||
(defn by-first-letter |
|||
"Returns a map from letters to a set of words that start with that letter" |
|||
[words] |
|||
(into {} (map (fn [[k v]] |
|||
[k (set v)])) |
|||
(group-by first words))) |
|||
(defn longest-path-from |
|||
"Find a longest path starting at word, using only words-by-first-letter for successive words. |
|||
Returns a pair of [length list-of-words] to describe the path." |
|||
[word words-by-first-letter] |
|||
(let [words-without-word (update words-by-first-letter (first word) |
|||
disj word) |
|||
next-words (words-without-word (last word))] |
|||
(if (empty? next-words) |
|||
[1 [word]] |
|||
(let [sub-paths (map #(longest-path-from % words-without-word) next-words) |
|||
[length words-of-path] (apply max-key first sub-paths)] |
|||
[(inc length) (cons word words-of-path)])))) |
|||
(defn longest-word-chain |
|||
"Find a longest path among the words in word-list, by performing a longest path search |
|||
starting at each word in the list." |
|||
[word-list] |
|||
(let [words-by-letter (by-first-letter word-list)] |
|||
(apply max-key first |
|||
(pmap #(longest-path-from % words-by-letter) |
|||
word-list)))) |
|||
(defn word-list-from-file [file-name] |
|||
(let [contents (slurp file-name) |
|||
words (clojure.string/split contents #"[ \n]")] |
|||
(filter #(not (empty? %)) words))) |
|||
(time (longest-word-chain (word-list-from-file "pokemon.txt")))</lang> |
|||
Evaluating the last line: |
|||
<lang clojure>"Elapsed time: 2867.337816 msecs" |
|||
[23 |
|||
("machamp" |
|||
"pinsir" |
|||
"relicanth" |
|||
"heatmor" |
|||
"registeel" |
|||
"landorus" |
|||
"seaking" |
|||
"girafarig" |
|||
"gabite" |
|||
"exeggcute" |
|||
"emboar" |
|||
"rufflet" |
|||
"trapinch" |
|||
"haxorus" |
|||
"simisear" |
|||
"remoraid" |
|||
"darmanitan" |
|||
"nosepass" |
|||
"scrafty" |
|||
"yamask" |
|||
"kricketune" |
|||
"emolga" |
|||
"audino")]</lang> |
|||
It initially ran in about 5 seconds, then I changed <code>map</code> to <code>pmap</code> (parallel map) in <code>longest-word-chain</code>. |
|||
This gave a nice speedup for a dual core laptop; the speedup for parallel searches was over 3x on a server. |
|||
=={{header|C sharp}}== |
=={{header|C sharp}}== |
||
Line 1,069: | Line 1,001: | ||
emolga |
emolga |
||
audino</pre> |
audino</pre> |
||
=={{header|Clojure}}== |
|||
<lang clojure>(ns rosetta-code.last-letter-first-letter |
|||
(:require clojure.string)) |
|||
(defn by-first-letter |
|||
"Returns a map from letters to a set of words that start with that letter" |
|||
[words] |
|||
(into {} (map (fn [[k v]] |
|||
[k (set v)])) |
|||
(group-by first words))) |
|||
(defn longest-path-from |
|||
"Find a longest path starting at word, using only words-by-first-letter for successive words. |
|||
Returns a pair of [length list-of-words] to describe the path." |
|||
[word words-by-first-letter] |
|||
(let [words-without-word (update words-by-first-letter (first word) |
|||
disj word) |
|||
next-words (words-without-word (last word))] |
|||
(if (empty? next-words) |
|||
[1 [word]] |
|||
(let [sub-paths (map #(longest-path-from % words-without-word) next-words) |
|||
[length words-of-path] (apply max-key first sub-paths)] |
|||
[(inc length) (cons word words-of-path)])))) |
|||
(defn longest-word-chain |
|||
"Find a longest path among the words in word-list, by performing a longest path search |
|||
starting at each word in the list." |
|||
[word-list] |
|||
(let [words-by-letter (by-first-letter word-list)] |
|||
(apply max-key first |
|||
(pmap #(longest-path-from % words-by-letter) |
|||
word-list)))) |
|||
(defn word-list-from-file [file-name] |
|||
(let [contents (slurp file-name) |
|||
words (clojure.string/split contents #"[ \n]")] |
|||
(filter #(not (empty? %)) words))) |
|||
(time (longest-word-chain (word-list-from-file "pokemon.txt")))</lang> |
|||
Evaluating the last line: |
|||
<lang clojure>"Elapsed time: 2867.337816 msecs" |
|||
[23 |
|||
("machamp" |
|||
"pinsir" |
|||
"relicanth" |
|||
"heatmor" |
|||
"registeel" |
|||
"landorus" |
|||
"seaking" |
|||
"girafarig" |
|||
"gabite" |
|||
"exeggcute" |
|||
"emboar" |
|||
"rufflet" |
|||
"trapinch" |
|||
"haxorus" |
|||
"simisear" |
|||
"remoraid" |
|||
"darmanitan" |
|||
"nosepass" |
|||
"scrafty" |
|||
"yamask" |
|||
"kricketune" |
|||
"emolga" |
|||
"audino")]</lang> |
|||
It initially ran in about 5 seconds, then I changed <code>map</code> to <code>pmap</code> (parallel map) in <code>longest-word-chain</code>. |
|||
This gave a nice speedup for a dual core laptop; the speedup for parallel searches was over 3x on a server. |
|||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
Line 1,193: | Line 1,193: | ||
"LOUDRED" "DARMANITAN" "NOSEPASS" "SIMISEAR" "RELICANTH" "HEATMOR" "RUFFLET" |
"LOUDRED" "DARMANITAN" "NOSEPASS" "SIMISEAR" "RELICANTH" "HEATMOR" "RUFFLET" |
||
"TRAPINCH" "HAXORUS" "SEAKING" "GIRAFARIG" "GABITE" "EXEGGCUTE" "EMOLGA" "AUDINO")</lang> |
"TRAPINCH" "HAXORUS" "SEAKING" "GIRAFARIG" "GABITE" "EXEGGCUTE" "EMOLGA" "AUDINO")</lang> |
||
=={{header|D}}== |
=={{header|D}}== |
||
===Simple Version=== |
===Simple Version=== |
||
Line 2,871: | Line 2,872: | ||
Yes No |
Yes No |
||
---------------------------</pre> |
---------------------------</pre> |
||
=={{header|PicoLisp}}== |
|||
<lang PicoLisp>(de pokemonChain (File) |
|||
(let Names (make (in File (while (read) (link @)))) |
|||
(for Name Names |
|||
(let C (last (chop Name)) |
|||
(set Name |
|||
(filter '((Nm) (pre? C Nm)) Names) ) ) ) |
|||
(let Res NIL |
|||
(for Name Names |
|||
(let Lst NIL |
|||
(recur (Name Lst) |
|||
(if (or (memq Name Lst) (not (val (push 'Lst Name)))) |
|||
(when (> (length Lst) (length Res)) |
|||
(setq Res Lst) ) |
|||
(mapc recurse (val Name) (circ Lst)) ) ) ) ) |
|||
(flip Res) ) ) )</lang> |
|||
Test: |
|||
<pre> |
|||
: (pokemonChain "pokemon.list") |
|||
-> (machamp petilil landorus scrafty yamask kricketune emboar registeel loudred |
|||
darmanitan nosepass simisear relicanth heatmor rufflet trapinch haxorus seaking |
|||
girafarig gabite exeggcute emolga audino) |
|||
: (length @) |
|||
-> 23 |
|||
</pre> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
Line 2,939: | Line 2,914: | ||
{{out}} |
{{out}} |
||
<pre>23: machamp petilil landorus seaking girafarig gabite emboar registeel loudred darmanitan nosepass simisear relicanth heatmor rufflet trapinch haxorus scrafty yamask kricketune exeggcute emolga audino</pre> |
<pre>23: machamp petilil landorus seaking girafarig gabite emboar registeel loudred darmanitan nosepass simisear relicanth heatmor rufflet trapinch haxorus scrafty yamask kricketune exeggcute emolga audino</pre> |
||
=={{header|Perl 6}}== |
|||
A breadth-first search that uses disk files to avoid memory exhaustion. Each candidate sequence is encoded at one character per name, so to avoid reuse of names we merely have to make sure there are no repeat characters in our encoded string. (The encoding starts at ASCII space for the first name, so newline is not among the encoded characters.) |
|||
<lang perl6>my @names = < |
|||
audino bagon baltoy banette bidoof braviary bronzor carracosta charmeleon |
|||
cresselia croagunk darmanitan deino emboar emolga exeggcute gabite |
|||
girafarig gulpin haxorus heatmor heatran ivysaur jellicent jumpluff kangaskhan |
|||
kricketune landorus ledyba loudred lumineon lunatone machamp magnezone mamoswine |
|||
nosepass petilil pidgeotto pikachu pinsir poliwrath poochyena porygon2 |
|||
porygonz registeel relicanth remoraid rufflet sableye scolipede scrafty seaking |
|||
sealeo silcoon simisear snivy snorlax spoink starly tirtouga trapinch treecko |
|||
tyrogue vigoroth vulpix wailord wartortle whismur wingull yamask |
|||
>; |
|||
my @last = @names.map: {.substr(*-1,1).ord } |
|||
my @succs = [] xx 128; |
|||
for @names.kv -> $i, $name { |
|||
my $ix = $name.ord; # $name.substr(0,1).ord |
|||
push @succs[$ix], $i; |
|||
} |
|||
my $OUT = open "llfl.new", :w orelse .die; |
|||
$OUT.print: chr($_ + 32),"\n" for 0 ..^ @names; |
|||
close $OUT; |
|||
my $new = +@names; |
|||
my $len = 1; |
|||
while $new { |
|||
say "Length { $len++ }: $new candidates"; |
|||
shell 'mv llfl.new llfl.known'; |
|||
my $IN = open "llfl.known" orelse .die; |
|||
my $OUT = open "llfl.new", :w orelse .die; |
|||
$new = 0; |
|||
loop { |
|||
my $cand = $IN.get // last; |
|||
for @succs[@last[$cand.ord - 32]][] -> $i { |
|||
my $ic = chr($i + 32); |
|||
next if $cand ~~ /$ic/; |
|||
$OUT.print: $ic,$cand,"\n"; |
|||
$new++; |
|||
} |
|||
} |
|||
$IN.close; |
|||
$OUT.close; |
|||
} |
|||
my $IN = open "llfl.known" orelse .die; |
|||
my $eg = $IN.lines.pick; |
|||
say "Length of longest: ", $eg.chars; |
|||
say join ' ', $eg.ords.reverse.map: { @names[$_ - 32] }</lang> |
|||
{{out}} |
|||
<pre>Length 1: 70 candidates |
|||
Length 2: 172 candidates |
|||
Length 3: 494 candidates |
|||
Length 4: 1288 candidates |
|||
Length 5: 3235 candidates |
|||
Length 6: 7731 candidates |
|||
Length 7: 17628 candidates |
|||
Length 8: 37629 candidates |
|||
Length 9: 75122 candidates |
|||
Length 10: 139091 candidates |
|||
Length 11: 236679 candidates |
|||
Length 12: 367405 candidates |
|||
Length 13: 516210 candidates |
|||
Length 14: 650916 candidates |
|||
Length 15: 733915 candidates |
|||
Length 16: 727566 candidates |
|||
Length 17: 621835 candidates |
|||
Length 18: 446666 candidates |
|||
Length 19: 260862 candidates |
|||
Length 20: 119908 candidates |
|||
Length 21: 40296 candidates |
|||
Length 22: 10112 candidates |
|||
Length 23: 1248 candidates |
|||
Length of longest: 23 |
|||
machamp petilil loudred darmanitan nosepass simisear rufflet trapinch heatmor registeel landorus starly yamask kricketune exeggcute emboar relicanth haxorus seaking girafarig gabite emolga audino</pre> |
|||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
Line 3,111: | Line 3,009: | ||
with word[1] when I got bored and killed it, quickly calculating at the very least another 4.5 days and |
with word[1] when I got bored and killed it, quickly calculating at the very least another 4.5 days and |
||
quite probably not finishing within my lifetime... |
quite probably not finishing within my lifetime... |
||
=={{header|PicoLisp}}== |
|||
<lang PicoLisp>(de pokemonChain (File) |
|||
(let Names (make (in File (while (read) (link @)))) |
|||
(for Name Names |
|||
(let C (last (chop Name)) |
|||
(set Name |
|||
(filter '((Nm) (pre? C Nm)) Names) ) ) ) |
|||
(let Res NIL |
|||
(for Name Names |
|||
(let Lst NIL |
|||
(recur (Name Lst) |
|||
(if (or (memq Name Lst) (not (val (push 'Lst Name)))) |
|||
(when (> (length Lst) (length Res)) |
|||
(setq Res Lst) ) |
|||
(mapc recurse (val Name) (circ Lst)) ) ) ) ) |
|||
(flip Res) ) ) )</lang> |
|||
Test: |
|||
<pre> |
|||
: (pokemonChain "pokemon.list") |
|||
-> (machamp petilil landorus scrafty yamask kricketune emboar registeel loudred |
|||
darmanitan nosepass simisear relicanth heatmor rufflet trapinch haxorus seaking |
|||
girafarig gabite exeggcute emolga audino) |
|||
: (length @) |
|||
-> 23 |
|||
</pre> |
|||
=={{header|Prolog}}== |
=={{header|Prolog}}== |
||
Line 3,685: | Line 3,609: | ||
Rufflet Braviary Vullaby Mandibuzz Heatmor Durant Deino Zweilous Hydreigon Larvesta Volcarona Cobalion Terrakion |
Rufflet Braviary Vullaby Mandibuzz Heatmor Durant Deino Zweilous Hydreigon Larvesta Volcarona Cobalion Terrakion |
||
Virizion Tornadus Thundurus Reshiram Zekrom Landorus Kyurem))</lang> |
Virizion Tornadus Thundurus Reshiram Zekrom Landorus Kyurem))</lang> |
||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
A breadth-first search that uses disk files to avoid memory exhaustion. Each candidate sequence is encoded at one character per name, so to avoid reuse of names we merely have to make sure there are no repeat characters in our encoded string. (The encoding starts at ASCII space for the first name, so newline is not among the encoded characters.) |
|||
<lang perl6>my @names = < |
|||
audino bagon baltoy banette bidoof braviary bronzor carracosta charmeleon |
|||
cresselia croagunk darmanitan deino emboar emolga exeggcute gabite |
|||
girafarig gulpin haxorus heatmor heatran ivysaur jellicent jumpluff kangaskhan |
|||
kricketune landorus ledyba loudred lumineon lunatone machamp magnezone mamoswine |
|||
nosepass petilil pidgeotto pikachu pinsir poliwrath poochyena porygon2 |
|||
porygonz registeel relicanth remoraid rufflet sableye scolipede scrafty seaking |
|||
sealeo silcoon simisear snivy snorlax spoink starly tirtouga trapinch treecko |
|||
tyrogue vigoroth vulpix wailord wartortle whismur wingull yamask |
|||
>; |
|||
my @last = @names.map: {.substr(*-1,1).ord } |
|||
my @succs = [] xx 128; |
|||
for @names.kv -> $i, $name { |
|||
my $ix = $name.ord; # $name.substr(0,1).ord |
|||
push @succs[$ix], $i; |
|||
} |
|||
my $OUT = open "llfl.new", :w orelse .die; |
|||
$OUT.print: chr($_ + 32),"\n" for 0 ..^ @names; |
|||
close $OUT; |
|||
my $new = +@names; |
|||
my $len = 1; |
|||
while $new { |
|||
say "Length { $len++ }: $new candidates"; |
|||
shell 'mv llfl.new llfl.known'; |
|||
my $IN = open "llfl.known" orelse .die; |
|||
my $OUT = open "llfl.new", :w orelse .die; |
|||
$new = 0; |
|||
loop { |
|||
my $cand = $IN.get // last; |
|||
for @succs[@last[$cand.ord - 32]][] -> $i { |
|||
my $ic = chr($i + 32); |
|||
next if $cand ~~ /$ic/; |
|||
$OUT.print: $ic,$cand,"\n"; |
|||
$new++; |
|||
} |
|||
} |
|||
$IN.close; |
|||
$OUT.close; |
|||
} |
|||
my $IN = open "llfl.known" orelse .die; |
|||
my $eg = $IN.lines.pick; |
|||
say "Length of longest: ", $eg.chars; |
|||
say join ' ', $eg.ords.reverse.map: { @names[$_ - 32] }</lang> |
|||
{{out}} |
|||
<pre>Length 1: 70 candidates |
|||
Length 2: 172 candidates |
|||
Length 3: 494 candidates |
|||
Length 4: 1288 candidates |
|||
Length 5: 3235 candidates |
|||
Length 6: 7731 candidates |
|||
Length 7: 17628 candidates |
|||
Length 8: 37629 candidates |
|||
Length 9: 75122 candidates |
|||
Length 10: 139091 candidates |
|||
Length 11: 236679 candidates |
|||
Length 12: 367405 candidates |
|||
Length 13: 516210 candidates |
|||
Length 14: 650916 candidates |
|||
Length 15: 733915 candidates |
|||
Length 16: 727566 candidates |
|||
Length 17: 621835 candidates |
|||
Length 18: 446666 candidates |
|||
Length 19: 260862 candidates |
|||
Length 20: 119908 candidates |
|||
Length 21: 40296 candidates |
|||
Length 22: 10112 candidates |
|||
Length 23: 1248 candidates |
|||
Length of longest: 23 |
|||
machamp petilil loudred darmanitan nosepass simisear rufflet trapinch heatmor registeel landorus starly yamask kricketune exeggcute emboar relicanth haxorus seaking girafarig gabite emolga audino</pre> |
|||
=={{header|REXX}}== |
=={{header|REXX}}== |
||
Line 3,996: | Line 3,998: | ||
22 emolga |
22 emolga |
||
23 audino</pre> |
23 audino</pre> |
||
=={{header|Rust}}== |
=={{header|Rust}}== |
||
{{trans|Kotlin}} |
{{trans|Kotlin}} |