Anagrams

From Rosetta Code

Jump to: navigation, search
Task
Anagrams
You are encouraged to solve this task according to the task description, using any language you may know.

Two or more words can be composed of the same characters, but in a different order. Using the word list at http://www.puzzlers.org/pub/wordlists/unixdict.txt, find the sets of words that share the same characters that contain the most words in them.

Contents

[edit] Ada

with Ada.Text_IO;  use Ada.Text_IO;
 
with Ada.Containers.Indefinite_Ordered_Maps;
with Ada.Containers.Indefinite_Ordered_Sets;
 
procedure Words_Of_Equal_Characters is
package Set_Of_Words is new Ada.Containers.Indefinite_Ordered_Sets (String);
use Ada.Containers, Set_Of_Words;
package Anagrams is new Ada.Containers.Indefinite_Ordered_Maps (String, Set);
use Anagrams;
 
File  : File_Type;
Result : Map;
Max  : Count_Type := 1;
 
procedure Put (Position : Anagrams.Cursor) is
First : Boolean := True;
List  : Set renames Element (Position);
procedure Put (Position : Set_Of_Words.Cursor) is
begin
if First then
First := False;
else
Put (',');
end if;
Put (Element (Position));
end Put;
begin
if List.Length = Max then
Iterate (List, Put'Access);
New_Line;
end if;
end Put;
 
begin
Open (File, In_File, "unixdict.txt");
loop
declare
Word : constant String  := Get_Line (File);
Key  : String (Word'Range) := (others => Character'Last);
List : Set;
Position : Anagrams.Cursor;
begin
for I in Word'Range loop
for J in Word'Range loop
if Key (J) > Word (I) then
Key (J + 1..I) := Key (J..I - 1);
Key (J) := Word (I);
exit;
end if;
end loop;
end loop;
Position := Find (Result, Key);
if Has_Element (Position) then
List := Element (Position);
Insert (List, Word);
Replace_Element (Result, Position, List);
else
Insert (List, Word);
Include (Result, Key, List);
end if;
Max := Count_Type'Max (Max, Length (List));
end;
end loop;
exception
when End_Error =>
Iterate (Result, Put'Access);
Close (File);
end Words_Of_Equal_Characters;

Sample output:

abel,able,bale,bela,elba
caret,carte,cater,crate,trace
angel,angle,galen,glean,lange
alger,glare,lager,large,regal
elan,lane,lean,lena,neal
evil,levi,live,veil,vile

[edit] AutoHotkey

contributed by Laszlo on the ahk forum

MsgBox % anagrams("able")
 
anagrams(word) {
Static dict
IfEqual dict,, FileRead dict, unixdict.txt ; file in the script directory
w := sort(word)
Loop Parse, dict, `n, `r
If (w = sort(A_LoopField))
t .= A_LoopField "`n"
Return t
}
 
sort(word) {
a := RegExReplace(word,".","$0`n")
Sort a
Return a
}

[edit] C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
 
char *sortedWord(const char *word, char *wbuf)
{
char *p1, *p2, *endwrd;
char t;
int swaps;
 
strcpy(wbuf, word);
endwrd = wbuf+strlen(wbuf);
do {
swaps = 0;
p1 = wbuf; p2 = endwrd-1;
while (p1<p2) {
if (*p2 > *p1) {
t = *p2; *p2 = *p1; *p1 = t;
swaps = 1;
}
p1++; p2--;
}
p1 = wbuf; p2 = p1+1;
while(p2 < endwrd) {
if (*p2 > *p1) {
t = *p2; *p2 = *p1; *p1 = t;
swaps = 1;
}
p1++; p2++;
}
} while (swaps);
return wbuf;
}
 
static
short cxmap[] = {
0x06, 0x1f, 0x4d, 0x0c, 0x5c, 0x28, 0x5d, 0x0e, 0x09, 0x33, 0x31, 0x56,
0x52, 0x19, 0x29, 0x53, 0x32, 0x48, 0x35, 0x55, 0x5e, 0x14, 0x27, 0x24,
0x02, 0x3e, 0x18, 0x4a, 0x3f, 0x4c, 0x45, 0x30, 0x08, 0x2c, 0x1a, 0x03,
0x0b, 0x0d, 0x4f, 0x07, 0x20, 0x1d, 0x51, 0x3b, 0x11, 0x58, 0x00, 0x49,
0x15, 0x2d, 0x41, 0x17, 0x5f, 0x39, 0x16, 0x42, 0x37, 0x22, 0x1c, 0x0f,
0x43, 0x5b, 0x46, 0x4b, 0x0a, 0x26, 0x2e, 0x40, 0x12, 0x21, 0x3c, 0x36,
0x38, 0x1e, 0x01, 0x1b, 0x05, 0x4e, 0x44, 0x3d, 0x04, 0x10, 0x5a, 0x2a,
0x23, 0x34, 0x25, 0x2f, 0x2b, 0x50, 0x3a, 0x54, 0x47, 0x59, 0x13, 0x57,
};
#define CXMAP_SIZE (sizeof(cxmap)/sizeof(short))
 
 
int Str_Hash( const char *key, int ix_max )
{
const char *cp;
short mash;
int hash = 33501551;
for (cp = key; *cp; cp++) {
mash = cxmap[*cp % CXMAP_SIZE];
hash = (hash >>4) ^ 0x5C5CF5C ^ ((hash<<1) + (mash<<5));
hash &= 0x3FFFFFFF;
}
return hash % ix_max;
}
 
typedef struct sDictWord *DictWord;
struct sDictWord {
const char *word;
DictWord next;
};
 
typedef struct sHashEntry *HashEntry;
struct sHashEntry {
const char *key;
HashEntry next;
DictWord words;
HashEntry link;
short wordCount;
};
 
#define HT_SIZE 8192
 
HashEntry hashTable[HT_SIZE];
 
HashEntry mostPerms = NULL;
 
int buildAnagrams( FILE *fin )
{
char buffer[40];
char bufr2[40];
char *hkey;
int hix;
HashEntry he, *hep;
DictWord we;
int maxPC = 2;
int numWords = 0;
 
while ( fgets(buffer, 40, fin)) {
for(hkey = buffer; *hkey && (*hkey!='\n'); hkey++);
*hkey = 0;
hkey = sortedWord(buffer, bufr2);
hix = Str_Hash(hkey, HT_SIZE);
he = hashTable[hix]; hep = &hashTable[hix];
while( he && strcmp(he->key , hkey) ) {
hep = &he->next;
he = he->next;
}
if ( ! he ) {
he = malloc(sizeof(struct sHashEntry));
he->next = NULL;
he->key = strdup(hkey);
he->wordCount = 0;
he->words = NULL;
he->link = NULL;
*hep = he;
}
we = malloc(sizeof(struct sDictWord));
we->word = strdup(buffer);
we->next = he->words;
he->words = we;
he->wordCount++;
if ( maxPC < he->wordCount) {
maxPC = he->wordCount;
mostPerms = he;
he->link = NULL;
}
else if (maxPC == he->wordCount) {
he->link = mostPerms;
mostPerms = he;
}
 
numWords++;
}
printf("%d words in dictionary max ana=%d\n", numWords, maxPC);
return maxPC;
}
 
 
int main( )
{
HashEntry he;
DictWord we;
FILE *f1;
 
f1 = fopen("unixdict.txt","r");
buildAnagrams(f1);
fclose(f1);
 
f1 = fopen("anaout.txt","w");
// f1 = stdout;
 
for (he = mostPerms; he; he = he->link) {
fprintf(f1,"%d:", he->wordCount);
for(we = he->words; we; we = we->next) {
fprintf(f1,"%s, ", we->word);
}
fprintf(f1, "\n");
}
 
fclose(f1);
return 0;
}

Output: (less than 1 second on old P500)

5:vile, veil, live, levi, evil, 
5:trace, crate, cater, carte, caret, 
5:regal, large, lager, glare, alger, 
5:neal, lena, lean, lane, elan, 
5:lange, glean, galen, angle, angel, 
5:elba, bela, bale, able, abel, 

[edit] C++

#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
 
 
int main() {
 
std::ifstream in("unixdict.txt");
typedef std::map<std::string, std::vector<std::string> > AnagramMap;
AnagramMap anagrams;
 
std::string word;
size_t count = 0;
while (std::getline(in, word)) {
std::string key = word;
std::sort(key.begin(), key.end());
// note: the [] op. automatically inserts a new value if key does not exist
AnagramMap::mapped_type & v = anagrams[key];
v.push_back(word);
count = std::max(count, v.size());
}
 
in.close();
 
for (AnagramMap::const_iterator it = anagrams.begin(), e = anagrams.end();
it != e; it++)
if (it->second.size() >= count) {
std::copy(it->second.begin(), it->second.end(),
std::ostream_iterator<std::string>(std::cout, ", "));
std::cout << std::endl;
}
return 0;
}

Output:

abel, able, bale, bela, elba, 
caret, carte, cater, crate, trace, 
angel, angle, galen, glean, lange, 
alger, glare, lager, large, regal, 
elan, lane, lean, lena, neal, 
evil, levi, live, veil, vile,

[edit] C#

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
 
namespace Anagram
{
class Program
{
static void Main(string[] args)
{
var words = File.ReadAllLines("unixdict.txt");
var groups = from w in words
group w by new String(w.ToCharArray().OrderBy(x => x).ToArray()) into c
where c.Count() > 1
orderby c.Count() descending
select c;
groups.ToList().ForEach(x => Console.WriteLine(String.Join(",", x.ToArray())));
}
}
}
 

output:

abel,able,bale,bela,elba
alger,glare,lager,large,regal
angel,angle,galen,glean,lange
caret,carte,cater,crate,trace
elan,lane,lean,lena,neal
evil,levi,live,veil,vile
abet,bate,beat,beta
aden,dane,dean,edna
aires,aries,arise,raise
amen,mane,mean,name
ames,mesa,same,seam
apt,pat,pta,tap
are,ear,era,rae
ate,eat,eta,tea
beard,bread,debar,debra
cereus,recuse,rescue,secure
dare,dear,erda,read
diet,edit,tide,tied
... etc

[edit] Clojure

Assume wordfile is the path of the local file containing the words. This code makes a map (groups) whose keys are sorted letters and values are lists of the key's anagrams. It then determines the length of the longest list, and prints out all the lists of that length.

(require '[clojure.java.io :as io])
 
(def groups
(with-open [r (io/reader wordfile)]
(group-by sort (line-seq r)))
 
(let [wordlists (sort-by (comp - count) (vals groups)
maxlength (count (first wordlists))]
(doseq [wordlist (take-while #(= (count %) maxlength) wordlists)]
(println wordlist))
 

[edit] Common Lisp

Library: DRAKMA to retrieve the wordlist.

(defun anagrams (&optional (url "http://www.puzzlers.org/pub/wordlists/unixdict.txt"))
(let ((words (drakma:http-request url :want-stream t))
(wordsets (make-hash-table :test 'equalp)))
;; populate the wordsets and close stream
(do ((word (read-line words nil nil) (read-line words nil nil)))
((null word) (close words))
(let ((letters (sort (copy-seq word) 'char<)))
(multiple-value-bind (pair presentp)
(gethash letters wordsets)
(if presentp
(setf (car pair) (1+ (car pair))
(cdr pair) (cons word (cdr pair)))
(setf (gethash letters wordsets)
(cons 1 (list word)))))))
;; find and return the biggest wordsets
(loop with maxcount = 0 with maxwordsets = '()
for pair being each hash-value of wordsets
if (> (car pair) maxcount)
do (setf maxcount (car pair)
maxwordsets (list (cdr pair)))
else if (eql (car pair) maxcount)
do (push (cdr pair) maxwordsets)
finally (return (values maxwordsets maxcount)))))

Evalutating

(multiple-value-bind (wordsets count) (anagrams)
(pprint wordsets)
(print count))

produces the following output.

(("vile" "veil" "live" "levi" "evil")
 ("regal" "large" "lager" "glare" "alger")
 ("lange" "glean" "galen" "angle" "angel")
 ("neal" "lena" "lean" "lane" "elan")
 ("trace" "crate" "cater" "carte" "caret")
 ("elba" "bela" "bale" "able" "abel"))
5

[edit] D

D 1, using Phobos (to download the word list you need the Tango Std Lib).

import std.stdio, std.stream;
 
void main() {
string[][string] anags;
int lmax;
foreach (string w; new BufferedFile("unixdict.txt")) {
string wrd = w.dup;
string key = wrd.sort;
anags[key] ~= wrd;
int len = anags[key].length;
lmax = lmax < len ? len : lmax;
}
foreach (a; anags) {
if (a.length == lmax) {
writefln(a);
}
}
}

D1 with Phobos and scrapple.tools extension library

import std.stdio, std.stream, tools.functional, tools.base;
 
void main() {
( (new BufferedFile("/usr/share/dict/cracklib-small"))
/map/ ex!("s -> s.dup")
/groupby/ ex!("s -> s.dup.sort")
/map/ (string key, string[] value) { return value; }
/qsort/ ex!("a, b -> a.length < b.length")
)[$-1].writefln();
}
 

[edit] E

println("Downloading...")
when (def wordText := <http://www.puzzlers.org/pub/wordlists/unixdict.txt> <- getText()) -> {
def words := wordText.split("\n")
 
def storage := [].asMap().diverge()
def anagramTable extends storage {
to get(key) { return storage.fetch(key, fn { storage[key] := [].diverge() }) }
}
 
println("Grouping...")
var largestGroupSeen := 0
for word in words {
def anagramGroup := anagramTable[word.sort()]
anagramGroup.push(word)
largestGroupSeen max= anagramGroup.size()
}
 
println("Selecting...")
for _ => anagramGroup ? (anagramGroup.size() == mostSeen) in anagramTable {
println(anagramGroup.snapshot())
}
}

[edit] F#

Read the lines in the dictionary, group by the sorted letters in each word, find the length of the longest sets of anagrams, extract the longest sequences of words sharing the same letters (i.e. anagrams):

let xss = Seq.groupBy (Array.ofSeq >> Array.sort) (System.IO.File.ReadAllLines "unixdict.txt")
Seq.map snd xss |> Seq.filter (Seq.length >> ( = ) (Seq.map (snd >> Seq.length) xss |> Seq.max))

Note that it is necessary to convert the sorted letters in each word from sequences to arrays because the groupBy function uses the default comparison and sequences do not compare structurally (but arrays do in F#).

Takes 0.8s to return:

 
val it : string seq seq =
seq
[seq ["abel"; "able"; "bale"; "bela"; "elba"];
seq ["alger"; "glare"; "lager"; "large"; "regal"];
seq ["angel"; "angle"; "galen"; "glean"; "lange"];
seq ["caret"; "carte"; "cater"; "crate"; "trace"];
seq ["elan"; "lane"; "lean"; "lena"; "neal"];
seq ["evil"; "levi"; "live"; "veil"; "vile"]]
 

[edit] Factor

"resource:unixdict.txt" utf8 file-lines
[ [ natural-sort >string ] keep ] { } map>assoc sort-keys
[ [ first ] compare +eq+ = ] monotonic-split
dup 0 [ length max ] reduce '[ length _ = ] filter [ values ] map .
{
{ "abel" "able" "bale" "bela" "elba" }
{ "caret" "carte" "cater" "crate" "trace" }
{ "angel" "angle" "galen" "glean" "lange" }
{ "alger" "glare" "lager" "large" "regal" }
{ "elan" "lane" "lean" "lena" "neal" }
{ "evil" "levi" "live" "veil" "vile" }
}

[edit] Fortran

This program:

 
!***************************************************************************************
module anagram_routines
!***************************************************************************************
implicit none
 
!the dictionary file:
integer,parameter :: file_unit = 1000
character(len=*),parameter :: filename = 'unixdict.txt'
 
!maximum number of characters in a word:
integer,parameter :: max_chars = 50
 
!maximum number of characters in the string displaying the anagram lists:
integer,parameter :: str_len = 256
 
type word
character(len=max_chars) :: str = repeat(' ',max_chars) !the word from the dictionary
integer :: n = 0 !length of this word
integer :: n_anagrams = 0 !number of anagrams found
logical :: checked = .false. !if this one has already been checked
character(len=str_len) :: anagrams = repeat(' ',str_len) !the anagram list for this word
end type word
 
!the dictionary structure:
type(word),dimension(:),allocatable,target :: dict
 
contains
!***************************************************************************************
 
!******************************************************************************
function count_lines_in_file(fid) result(n_lines)
!******************************************************************************
implicit none
 
integer :: n_lines
integer,intent(in) :: fid
character(len=1) :: tmp
integer :: i
integer :: ios
 
!the file is assumed to be open already.
 
rewind(fid) !rewind to beginning of the file
 
n_lines = 0
do !read each line until the end of the file.
read(fid,'(A1)',iostat=ios) tmp
if (ios < 0) exit !End of file
n_lines = n_lines + 1 !row counter
end do
 
rewind(fid) !rewind to beginning of the file
 
!******************************************************************************
end function count_lines_in_file
!******************************************************************************
 
!******************************************************************************
pure elemental function is_anagram(x,y)
!******************************************************************************
implicit none
character(len=*),intent(in) :: x
character(len=*),intent(in) :: y
logical :: is_anagram
 
character(len=len(x)) :: x_tmp !a copy of x
integer :: i,j
 
!a character not found in any word:
character(len=1),parameter :: null = achar(0)
 
!x and y are assumed to be the same size.
 
x_tmp = x
do i=1,len_trim(x)
j = index(x_tmp, y(i:i)) !look for this character in x_tmp
if (j/=0) then
x_tmp(j:j) = null !clear it so it won't be checked again
else
is_anagram = .false. !character not found: x,y are not anagrams
return
end if
end do
 
!if we got to this point, all the characters
! were the same, so x,y are anagrams:
is_anagram = .true.
 
!******************************************************************************
end function is_anagram
!******************************************************************************
 
!***************************************************************************************
end module anagram_routines
!***************************************************************************************
 
!***************************************************************************************
program main
!***************************************************************************************
use anagram_routines
implicit none
 
integer :: n,i,j,n_max
type(word),pointer :: x,y
logical :: first_word
real :: start, finish
 
call cpu_time(start) !..start timer
 
!open the dictionary and read in all the words:
open(unit=file_unit,file=filename) !open the file
n = count_lines_in_file(file_unit) !count lines in the file
allocate(dict(n)) !allocate dictionary structure
do i=1,n !
read(file_unit,'(A)') dict(i)%str !each line is a word in the dictionary
dict(i)%n = len_trim(dict(i)%str) !saving length here to avoid trim's below
end do
close(file_unit) !close the file
 
!search dictionary for anagrams:
do i=1,n
 
x => dict(i) !pointer to simplify code
first_word = .true. !initialize
 
do j=i,n
 
y => dict(j) !pointer to simplify code
 
!checks to avoid checking words unnecessarily:
if (x%checked .or. y%checked) cycle !both must not have been checked already
if (x%n/=y%n) cycle !must be the same size
if (x%str(1:x%n)==y%str(1:y%n)) cycle !can't be the same word
 
! check to see if x,y are anagrams:
if (is_anagram(x%str(1:x%n), y%str(1:y%n))) then
!they are anagrams.
y%checked = .true. !don't check this one again.
x%n_anagrams = x%n_anagrams + 1
if (first_word) then
!this is the first anagram found for this word.
first_word = .false.
x%n_anagrams = x%n_anagrams + 1
x%anagrams = trim(x%anagrams)//x%str(1:x%n) !add first word to list
end if
x%anagrams = trim(x%anagrams)//','//y%str(1:y%n) !add next word to list
end if
 
end do
x%checked = .true. !don't check this one again
 
end do
 
!anagram groups with the most words:
write(*,*) ''
n_max = maxval(dict%n_anagrams)
do i=1,n
if (dict(i)%n_anagrams==n_max) write(*,'(A)') trim(dict(i)%anagrams)
end do
 
!anagram group containing longest words:
write(*,*) ''
n_max = maxval(dict%n, mask=dict%n_anagrams>0)
do i=1,n
if (dict(i)%n_anagrams>0 .and. dict(i)%n==n_max) write(*,'(A)') trim(dict(i)%anagrams)
end do
write(*,*) ''
 
call cpu_time(finish) !...stop timer
write(*,'(A,F6.3,A)') '[Runtime = ',finish-start,' sec]'
write(*,*) ''
 
!***************************************************************************************
end program main
!***************************************************************************************
 

produces this output:

	abel,able,bale,bela,elba
	alger,glare,lager,large,regal
	angel,angle,galen,glean,lange
	caret,carte,cater,crate,trace
	elan,lane,lean,lena,neal
	evil,levi,live,veil,vile
	 
	conservation,conversation

	[Runtime =  6.897 sec]

[edit] Groovy

This program:

def words = new URL('http://www.puzzlers.org/pub/wordlists/unixdict.txt').text.readLines()
def groups = words.groupBy{ it.toList().sort() }
def bigGroupSize = groups.collect{ it.value.size() }.max()
def isBigAnagram = { it.value.size() == bigGroupSize }
println groups.findAll(isBigAnagram).collect{ it.value }.collect{ it.join(' ') }.join('\n')

produces this output:

abel able bale bela elba
alger glare lager large regal
angel angle galen glean lange
caret carte cater crate trace
elan lane lean lena neal
evil levi live veil vile

[edit] Haskell

import Data.List
 
groupon f x y = f x == f y
 
main = do
f <- readFile "./../Puzzels/Rosetta/unixdict.txt"
let words = lines f
wix = groupBy (groupon fst) . sort $ zip (map sort words) words
mxl = maximum $ map length wix
mapM_ (print . map snd) . filter ((==mxl).length) $ wix

Sample output:

*Main> main
["abel","able","bale","bela","elba"]
["caret","carte","cater","crate","trace"]
["angel","angle","galen","glean","lange"]
["alger","glare","lager","large","regal"]
["elan","lane","lean","lena","neal"]
["evil","levi","live","veil","vile"]

[edit] Icon and Unicon

[edit] Icon

 procedure main(args)
every writeSet(!getLongestAnagramSets()
end
 
procedure getLongestAnagramSets()
wordSets := table()
longestWSet := 0
longSets := set()
 
every word := !&input do {
wChars := csort(word)
/wordSets[wChars] := set()
insert(wordSets[wChars], word)
 
if 1 < *wordSets[wChars} == longestWSet then
insert(longSets, wordSets[wChars])
if 1 < *wordSets[wChars} > longestWSet then {
longestWSet := *wordSets[wChars}
longSets := set([wordSets[wChars]])
}
}
 
return longSets
end
 
procedure writeSet(words)
every writes("\t"|!words," ")
write()
end
 
procedure csort(w)
every (s := "") ||:= (find(c := !cset(w),w),c)
return s
end


Sample run:

->an <unixdict.txt
         abel bale bela able elba 
         lean neal elan lane lena 
         angle galen lange angel glean 
         alger glare lager large regal 
         veil evil levi live vile 
         caret cater crate carte trace
->

[edit] Unicon

The Icon solution works in Unicon.

[edit] J

   (#~ a: ~: {:"1) (]/.~ /:~&>) <;._2 ] 1!:1 <'unixdict.txt'
+-----+-----+-----+-----+-----+
|abel |able |bale |bela |elba |
+-----+-----+-----+-----+-----+
|alger|glare|lager|large|regal|
+-----+-----+-----+-----+-----+
|angel|angle|galen|glean|lange|
+-----+-----+-----+-----+-----+
|caret|carte|cater|crate|trace|
+-----+-----+-----+-----+-----+
|elan |lane |lean |lena |neal |
+-----+-----+-----+-----+-----+
|evil |levi |live |veil |vile |
+-----+-----+-----+-----+-----+

Explanation:

   <;._2 ] 1!:1 <'unixdict.txt'

This reads in the dictionary and produces a list of boxes. Each box contains one line (one word) from the dictionary.

   (]/.~ /:~&>)

This groups the words into rows where anagram equivalents appear in the same row.

   (#~ a: ~: {:"1)

This selects rows whose last element is not an empty box.

[edit] Java

Works with: Java version 1.5+

The key to this algorithm is the sorting of the characters in each word from the dictionary. The line Arrays.sort(chars); sorts all of the letters in the word in ascending order using a built-in quicksort, so all of the words in the first group in the result end up under the key "aegln" in the anagrams map.

import java.net.*;
import java.io.*;
import java.util.*;
 
public class WordsOfEqChars {
public static void main(String[] args) throws IOException {
URL url = new URL("http://www.puzzlers.org/pub/wordlists/unixdict.txt");
InputStreamReader isr = new InputStreamReader(url.openStream());
BufferedReader reader = new BufferedReader(isr);
 
Map<String, Collection<String>> anagrams = new HashMap<String, Collection<String>>();
String word;
int count = 0;
while ((word = reader.readLine()) != null) {
char[] chars = word.toCharArray();
Arrays.sort(chars);
String key = new String(chars);
if (!anagrams.containsKey(key))
anagrams.put(key, new ArrayList<String>());
anagrams.get(key).add(word);
count = Math.max(count, anagrams.get(key).size());
}
 
reader.close();
 
for (Collection<String> ana : anagrams.values())
if (ana.size() >= count)
System.out.println(ana);
}
}

Output:

[angel, angle, galen, glean, lange]
[elan, lane, lean, lena, neal]
[alger, glare, lager, large, regal]
[abel, able, bale, bela, elba]
[evil, levi, live, veil, vile]
[caret, carte, cater, crate, trace]

[edit] Liberty BASIC

a$ = "large"
open "unixdict.txt" for input as #1
list$ = Input$(#1, lof(#1))
close #1
tmp$ = permutation$(list$, "", a$)
print "** End of List **"
end
 
function permutation$(list$, pre$, post$)
lgth = len(post$)
if lgth < 2 then
if instr(list$, chr$(10);pre$;post$;chr$(10)) > 0 then
print pre$;post$
end if
else
for i = 1 to lgth
tmp$ = permutation$(list$, pre$ + mid$(post$, i, 1), left$(post$, i - 1) + right$(post$, lgth - i))
next i
end if
end function

[edit] Lua

Lua's core library is very small and does not include built-in network functionality. If a networking library were imported, the local file in the following script could be replaced with the remote dictionary file. This may or may not be a good implementation, but I thought the method was interesting.

-- Build the word set
local set = {}
local file = io.open("unixdict.txt")
local str = file:read()
while str do
table.insert(set,str)
str = file:read()
end
 
-- Build the anagram tree
local tree = {}
for i,word in next,set do
-- Sort a string from lowest char to highest
local function sortString(str)
if #str <= 1 then
return str
end
local less = ''
local greater = ''
local pivot = str:byte(1)
for i = 2, #str do
if str:byte(i) <= pivot then
less = less..(str:sub(i,i))
else
greater = greater..(str:sub(i,i))
end
end
return sortString(less)..str:sub(1,1)..sortString(greater)
end
local sortchar = sortString(word)
if not tree[#word] then tree[#word] = {} end
local node = tree[#word]
for i = 1,#word do
if not node[sortchar:byte(i)] then
node[sortchar:byte(i)] = {}
end
node = node[sortchar:byte(i)]
end
table.insert(node,word)
end
 
-- Gather largest groups by gathering all groups of current max size and droping gathered groups and increasing max when a new largest group is found
local max = 0
local set = {}
local function recurse (tree)
local num = 0
for i,node in next,tree do
if type(node) == 'string' then
num = num + 1
end
end
if num > max then
set = {}
max = num
end
if num == max then
local newset = {}
for i,node in next,tree do
if type(node) == 'string' then
table.insert(newset,node)
end
end
table.insert(set,newset)
end
for i,node in next,tree do
if type(node) == 'table' then
recurse(node)
end
end
end
 
recurse (tree)
for i,v in next,set do io.write (i..':\t')for j,u in next,v do io.write (u..' ') end print() end

[edit] M4

divert(-1)
changequote(`[',`]')
define([for],
[ifelse($#,0,[[$0]],
[ifelse(eval($2<=$3),1,
[pushdef([$1],$2)$4[]popdef([$1])$0([$1],incr($2),$3,[$4])])])])
define([_bar],include(t.txt))
define([eachlineA],
[ifelse(eval($2>0),1,
[$3(substr([$1],0,$2))[]eachline(substr([$1],incr($2)),[$3])])])
define([eachline],[eachlineA([$1],index($1,[
]),[$2])])
define([removefirst],
[substr([$1],0,$2)[]substr([$1],incr($2))])
define([checkfirst],
[ifelse(eval(index([$2],substr([$1],0,1))<0),1,
0,
[ispermutation(substr([$1],1),
removefirst([$2],index([$2],substr([$1],0,1))))])])
define([ispermutation],
[ifelse([$1],[$2],1,
eval(len([$1])!=len([$2])),1,0,
len([$1]),0,0,
[checkfirst([$1],[$2])])])
define([_set],[define($1<$2>,$3)])
define([_get],[defn([$1<$2>])])
define([_max],1)
define([_n],0)
define([matchj],
[_set([count],$2,incr(_get([count],$2)))[]ifelse(eval(_get([count],$2)>_max),
1,[define([_max],incr(_max))])[]_set([list],$2,[_get([list],$2) $1])])
define([checkwordj],
[ifelse(ispermutation([$1],_get([word],$2)),1,[matchj([$1],$2)],
[addwordj([$1],incr($2))])])
define([_append],
[_set([word],_n,[$1])[]_set([count],_n,1)[]_set([list],_n,
[$1 ])[]define([_n],incr(_n))])
define([addwordj],
[ifelse($2,_n,[_append([$1])],[checkwordj([$1],$2)])])
define([addword],
[addwordj([$1],0)])
divert
eachline(_bar,[addword])
_max
for([x],1,_n,[ifelse(_get([count],x),_max,[_get([list],x)
])])

Memory limitations keep this program from working on the full-sized dictionary. Run against the first 100 words, here is the output:

2
abel  able
aboard  abroad

[edit] Mathematica

Download the dictionary, split the lines, split the word in characters and sort them. Now sort by those words, and find sequences of equal 'letter-hashes'. Return the longest sequences:

list=Import["http://www.puzzlers.org/pub/wordlists/unixdict.txt","Lines"];
text={#,StringJoin@@Sort[Characters[#]]}&/@list;
text=SortBy[text,#[[2]]&];
splits=Split[text,#1[[2]]==#2[[2]]&][[All,All,1]];
maxlen=Max[Length/@splits];
Select[splits,Length[#]==maxlen&]

gives back:

{{abel,able,bale,bela,elba},{caret,carte,cater,crate,trace},{angel,angle,galen,glean,lange},{alger,glare,lager,large,regal},{elan,lane,lean,lena,neal},{evil,levi,live,veil,vile}}

An alternative is faster, but requires version 7 (for Gather):

splits = Gather[list, Sort[Characters[#]] == Sort[Characters[#2]] &];
maxlen = Max[Length /@ splits];
Select[splits, Length[#] == maxlen &]

Also, Mathematica's own word list is available; replacing the list definition with list = WordData[]; and forcing maxlen to 5 yields instead this result:

{{angered,derange,enraged,grandee,grenade},
 {anisometric,creationism,miscreation,reactionism,romanticise},
 {aper,pare,pear,rape,reap},
 {ardeb,barde,bared,beard,bread,debar},
 {aril,lair,lari,liar,lira,rail,rial},
 {aster,rates,stare,tears,teras},
 {caret,carte,cater,crate,react,trace},
 {east,eats,sate,seat,seta},
 {ester,reset,steer,teres,terse},
 {inert,inter,niter,nitre,trine},
 {latrine,ratline,reliant,retinal,trenail},
 {least,slate,stale,steal,stela,tesla},
 {luster,lustre,result,rustle,sutler,ulster},
 {merit,miter,mitre,remit,timer},
 {part,prat,rapt,tarp,trap},
 {resin,rinse,risen,serin,siren},
 {respect,scepter,sceptre,specter,spectre}}


[edit] MUMPS

Anagrams	New ii,file,longest,most,sorted,word
Set file="unixdict.txt"
Open file:"r" Use file
For Quit:$ZEOF DO
. New char,sort
. Read word Quit:word=""
. For ii=1:1:$Length(word) Do
. . Set char=$ASCII(word,ii)
. . If char>64,char<91 Set char=char+32
. . Set sort(char)=$Get(sort(char))+1
. . Quit
. Set (sorted,char)="" For Set char=$Order(sort(char)) Quit:char="" Do
. . For ii=1:1:sort(char) Set sorted=sorted_$Char(char)
. . Quit
. Set table(sorted,word)=1
. Quit
Close file
Set sorted="" For Set sorted=$Order(table(sorted)) Quit:sorted="" Do
. Set ii=0,word="" For Set word=$Order(table(sorted,word)) Quit:word="" Set ii=ii+1
. Quit:ii<2
. Set most(ii,sorted)=1
. Quit
Write !,"The anagrams with the most variations:"
Set ii=$Order(most(""),-1)
Set sorted="" For Set sorted=$Order(most(ii,sorted)) Quit:sorted="" Do
. Write ! Set word="" For Set word=$Order(table(sorted,word)) Quit:word="" Write " ",word
. Quit
Write !,"The longest anagrams:"
Set ii=$Order(longest(""),-1)
Set sorted="" For Set sorted=$Order(longest(ii,sorted)) Quit:sorted="" Do
. Write ! Set word="" For Set word=$Order(table(sorted,word)) Quit:word="" Write " ",word
. Quit
Quit
 
Do Anagrams
 
The anagrams with the most variations:
abel able bale bela elba
caret carte cater crate trace
angel angle galen glean lange
alger glare lager large regal
elan lane lean lena neal
evil levi live veil vile
The longest anagrams:
conservation conversation




[edit] OCaml

let explode str =
let l = ref [] in
let len = String.length str in
for i = len - 1 downto 0 do
l := str.[i] :: !l
done;
(!l)
 
let implode li =
let len = List.length li in
let s = String.create len in
let i = ref 0 in
List.iter (fun c -> s.[!i] <- c; incr i) li;
(s)
 
let () =
let h = Hashtbl.create 3571 in
let ic = open_in "unixdict.txt" in
try while true do
let w = input_line ic in
let k = implode(List.sort compare (explode w)) in
let l =
try Hashtbl.find h k
with Not_found -> []
in
Hashtbl.add h k (w::l);
done with End_of_file -> ();
let n = Hashtbl.fold (fun _ lw n -> max n (List.length lw)) h 0 in
Hashtbl.iter (fun _ lw ->
if List.length lw >= n then
( List.iter (Printf.printf " %s") lw;
print_newline())
) h;
;;

[edit] Oz

declare
%% Helper function
fun {ReadLines Filename}
File = {New class $ from Open.file Open.text end init(name:Filename)}
in
for collect:C break:B do
case {File getS($)} of false then {File close} {B}
[] Line then {C Line}
end
end
end
 
%% Groups anagrams by using a mutable dictionary
%% with sorted words as keys
WordDict = {Dictionary.new}
for Word in {ReadLines "unixdict.txt"} do
Keyword = {String.toAtom {Sort Word Value.'<'}}
in
WordDict.Keyword := Word|{CondSelect WordDict Keyword nil}
end
Sets = {Dictionary.items WordDict}
 
%% Filter such that only the largest sets remain
MaxSetSize = {FoldL {Map Sets Length} Max 0}
LargestSets = {Filter Sets fun {$ S} {Length S} == MaxSetSize end}
in
%% Display result (make sure strings are shown as string, not as number lists)
{Inspector.object configureEntry(widgetShowStrings true)}
{Inspect LargestSets}

[edit] Perl

use LWP::Simple;
use List::Util qw(max);
 
my @words = split(' ', get('http://www.puzzlers.org/pub/wordlists/unixdict.txt'));
my %anagram;
foreach my $word (@words) {
push @{ $anagram{join('', sort(split(//, $word)))} }, $word;
}
 
my $count = max(map {scalar @$_} values %anagram);
foreach my $ana (values %anagram) {
if (@$ana >= $count) {
print "@$ana\n";
}
}

refactor of above:

use LWP::Simple;
 
for (split ' ' => get 'http://www.puzzlers.org/pub/wordlists/unixdict.txt')
{push @{$anagram{ join '' => sort split // }}, $_}
 
$max > @$_ or $max = @$_ for values %anagram;
@$_ >= $max and print "@$_\n" for values %anagram;

Output:

alger glare lager large regal
abel able bale bela elba
evil levi live veil vile
angel angle galen glean lange
elan lane lean lena neal
caret carte cater crate trace

[edit] Perl 6

my $url = 'http://www.puzzlers.org/pub/wordlists/unixdict.txt';
 
my %anagram = uri($url).words.classify( { .comb.sort.join } );
 
my $max = [max] map { +@($_) }, %anagram.values;
 
%anagram.values.grep( { +@($_) >= $max } )».join(' ')».say;
 

Output:

caret carte cater crate trace
angel angle galen glean lange
alger glare lager large regal
elan lane lean lena neal
evil levi live veil vile
abel able bale bela elba

[edit] PHP

<?php
$words = explode("\n", file_get_contents('http://www.puzzlers.org/pub/wordlists/unixdict.txt'));
foreach ($words as $word) {
$chars = str_split($word);
sort($chars);
$anagram[implode($chars)][] = $word;
}
 
$best = max(array_map('count', $anagram));
foreach ($anagram as $ana)
if (count($ana) == $best)
print_r($ana);
?>

[edit] PicoLisp

A straight-forward implementation using 'group' takes 48 seconds on a 1.7 GHz Pentium:

(flip
(by length sort
(by '((L) (sort (copy L))) group
(in "unixdict.txt" (make (while (line) (link @)))) ) ) )

Using a binary tree with the 'idx' function, it takes only 0.42 seconds on the same machine, a factor of 100 faster:

(let Words NIL
(in "unixdict.txt"
(while (line)
(let (Word (pack @) Key (pack (sort @)))
(if (idx 'Words Key T)
(push (car @) Word)
(set Key (list Word)) ) ) ) )
(flip (by length sort (mapcar val (idx 'Words)))) )

Output:

-> (("vile" "veil" "live" "levi" "evil") ("trace" "crate" "cater" "carte" "caret
") ("regal" "large" "lager" "glare" "alger") ("neal" "lena" "lean" "lane" "elan"
) ("lange" "glean" "galen" "angle" "angel") ("elba" "bela" "bale" "able" "abel")
 ("tulsa" "talus" "sault" "latus") ...

[edit] PL/I

 
/* Search a list of words, finding those having the same letters. */
 
word_test: proc options (main);
declare words (50000) character (20) varying,
frequency (50000) fixed binary;
declare word character (20) varying;
declare (i, k, wp, most) fixed binary (31);
 
on endfile (sysin) go to done;
 
words = ''; frequency = 0;
wp = 0;
do forever;
get edit (word) (L);
call search_word_list (word);
end;
 
done:
put skip list ('There are ' || wp || ' words');
most = 0;
/* Determine the word(s) having the greatest number of anagrams. */
do i = 1 to wp;
if most < frequency(i) then most = frequency(i);
end;
put skip edit ('The following word(s) have ', trim(most), ' anagrams:') (a);
put skip;
do i = 1 to wp;
if most = frequency(i) then put edit (words(i)) (x(1), a);
end;
 
search_word_list: procedure (word) options (reorder);
declare word character (*) varying;
declare i fixed binary (31);
 
do i = 1 to wp;
if length(words(i)) = length(word) then
if is_anagram(word, words(i)) then
do;
frequency(i) = frequency(i) + 1;
return;
end;
end;
/* The word does not exist in the list, so add it. */
if wp >= hbound(words,1) then return;
wp = wp + 1;
words(wp) = word;
frequency(wp) = 1;
return;
end search_word_list;
 
/* Returns true if the words are anagrams, otherwise returns false. */
is_anagram: procedure (word1, word2) returns (bit(1)) options (reorder);
declare (word1, word2) character (*) varying;
declare tword character (20) varying, c character (1);
declare (i, j) fixed binary;
 
tword = word2;
do i = 1 to length(word1);
c = substr(word1, i, 1);
j = index(tword, c);
if j = 0 then return ('0'b);
substr(tword, j, 1) = ' ';
end;
return ('1'b);
end is_anagram;
 
end word_test;
 

Output:

 
There are 23565 words
The following word(s) have 5 anagrams:
abel alger angel caret elan evil
 

[edit] PowerShell

Works with: PowerShell version 2

$c = New-Object Net.WebClient
$words = -split ($c.DownloadString('http://www.puzzlers.org/pub/wordlists/unixdict.txt'))
$top_anagrams = $words `
| ForEach-Object {
$_ | Add-Member -PassThru NoteProperty Characters `
(-join (([char[]] $_) | Sort-Object))
} `
| Group-Object Characters `
| Group-Object Count `
| Sort-Object Count `
| Select-Object -First 1
 
$top_anagrams.Group | ForEach-Object { $_.Group -join ', ' }

Output:

abel, able, bale, bela, elba
alger, glare, lager, large, regal
angel, angle, galen, glean, lange
caret, carte, cater, crate, trace
elan, lane, lean, lena, neal
evil, levi, live, veil, vile

[edit] Prolog

Works with: SWI-Prolog version 5.10.0

:- use_module(library( http/http_open )).
 
 
anagrams:-
% we read the URL of the words
http_open('http://www.puzzlers.org/pub/wordlists/unixdict.txt', In, []),
read_file(In, [], Out),
close(In),
 
% we get a list of pairs key-value where key = a-word value = <list-of-its-codes>
% this list must be sorted
msort(Out, MOut),
 
% in order to gather values with the same keys
group_pairs_by_key(MOut, GPL),
 
% we sorted this list in decreasing order of the length of values
predsort(my_compare, GPL, GPLSort),
 
% we extract the first 6 items
GPLSort = [_H1-T1, _H2-T2, _H3-T3, _H4-T4, _H5-T5, _H6-T6 | _],
 
% Tnn are lists of codes (97 for 'a'), we create the strings
maplist(maplist(atom_codes), L, [T1, T2, T3, T4, T5, T6] ),
 
maplist(writeln, L).
 
 
read_file(In, L, L1) :-
read_line_to_codes(In, W),
( W == end_of_file ->
% the file is read
L1 = L
;
% we sort the list of codes of the line
msort(W, W1),
 
% to create the key in alphabetic order
atom_codes(A, W1),
 
% and we have the pair Key-Value in the result list
read_file(In, [A-W | L], L1)).
 
% predicate for sorting list of pairs Key-Values
% if the lentgh of values is the same
% we sort the keys in alhabetic order
my_compare(R, K1-V1, K2-V2) :-
length(V1, L1),
length(V2, L2),
( L1 < L2 -> R = >; L1 > L2 -> R = <; compare(R, K1, K2)).
 

The result is

[abel,able,bale,bela,elba]
[caret,carte,cater,crate,trace]
[angel,angle,galen,glean,lange]
[alger,glare,lager,large,regal]
[elan,lane,lean,lena,neal]
[evil,levi,live,veil,vile]
true

[edit] PureBasic

Works with: PureBasic version 4.4

InitNetwork()  ;
OpenConsole()
 
Procedure.s sortWord(word$)
len.i = Len(word$)
Dim CharArray.s (len)
 
For n = 1 To len ; Transfering each single character
CharArray(n) = Mid(word$, n, 1) ; of the word into an array.
Next
 
SortArray(CharArray(),#PB_Sort_NoCase ) ; Sorting the array.
 
word$ =""
For n = 1 To len ; Writing back each single
word$ + CharArray(n) ; character of the array.
Next
 
ProcedureReturn word$
EndProcedure
 
 
tmpdir$ = GetTemporaryDirectory()
filename$ = tmpdir$ + "unixdict.txt"
Structure ana
isana.l
anas.s
EndStructure
 
NewMap anaMap.ana()
 
If ReceiveHTTPFile("http://www.puzzlers.org/pub/wordlists/unixdict.txt", filename$)
If ReadFile(1, filename$)
Repeat
word$ = (ReadString(1)) ; Reading a word from a file.
key$ = (sortWord(word$)) ; Sorting the word and storing in key$.
 
If FindMapElement(anaMap(), key$) ; Looking up if a word already had the same key$.
 
; if yes
anaMap()\anas = anaMap()\anas+ ", " + word$ ; adding the word
anaMap()\isana + 1
Else
; if no
anaMap(key$)\anas = word$ ; applying a new record
anaMap()\isana + 1
EndIf
Until Eof(1)
CloseFile(1)
DeleteFile(filename$)
 
;----- output -----
ForEach anaMap()
If anaMap()\isana >= 4 ; only emit what had 4 or more hits.
PrintN(anaMap()\anas)
EndIf
Next
 
PrintN("Press any key"): Repeat: Until Inkey() <> ""
EndIf
EndIf

[edit] Python

Python 2.5 shell input (IDLE)

>>> import urllib
>>> from collections import defaultdict
>>> words = urllib.urlopen('http://www.puzzlers.org/pub/wordlists/unixdict.txt').read().split()
>>> len(words)
25104
>>> anagram = defaultdict(list) # map sorted chars to anagrams
>>> for word in words:
anagram[tuple(sorted(word))].append( word )
 
 
>>> count = max(len(ana) for ana in anagram.itervalues())
>>> for ana in anagram.itervalues():
if len(ana) >= count:
print ana
 
 
['angel', 'angle', 'galen', 'glean', 'lange']
['alger', 'glare', 'lager', 'large', 'regal']
['caret', 'carte', 'cater', 'crate', 'trace']
['evil', 'levi', 'live', 'veil', 'vile']
['elan', 'lane', 'lean', 'lena', 'neal']
['abel', 'able', 'bale', 'bela', 'elba']
>>> count
5
>>>

Translation of: Haskell Works with: Python version 2.6 sort and then group using groupby()

>>> import urllib, itertools
>>> words = urllib.urlopen('http://www.puzzlers.org/pub/wordlists/unixdict.txt').read().split()
>>> len(words)
25104
>>> anagrams = [list(g) for k,g in itertools.groupby(sorted(words, key=sorted), key=sorted)]
 
 
>>> count = max(len(ana) for ana in anagrams)
>>> for ana in anagrams:
if len(ana) >= count:
print ana
 
 
['abel', 'able', 'bale', 'bela', 'elba']
['caret', 'carte', 'cater', 'crate', 'trace']
['angel', 'angle', 'galen', 'glean', 'lange']
['alger', 'glare', 'lager', 'large', 'regal']
['elan', 'lane', 'lean', 'lena', 'neal']
['evil', 'levi', 'live', 'veil', 'vile']
>>> count
5
>>>


[edit] R

 
words <- readLines("http://www.puzzlers.org/pub/wordlists/unixdict.txt")
word_group <- sapply(
strsplit(words, split=""), # this will split all words to single letters...
function(x) paste(sort(x), collapse="") # ...which we sort and paste again
)
 
counts <- tapply(words, word_group, length) # group words by class to get number of anagrams
anagrams <- tapply(words, word_group, paste, collapse=", ") # group to get string with all anagrams
 
# Results
table(counts)
counts
1 2 3 4 5
22263 1111 155 31 6
 
anagrams[counts == max(counts)]
abel acert
"abel, able, bale, bela, elba" "caret, carte, cater, crate, trace"
aegln aeglr
"angel, angle, galen, glean, lange" "alger, glare, lager, large, regal"
aeln eilv
"elan, lane, lean, lena, neal" "evil, levi, live, veil, vile"
 
 

[edit] Revolution

on mouseUp
repeat for each word W in url "http://www.puzzlers.org/pub/wordlists/unixdict.txt"
put W & comma after A[sortChars(W)]
end repeat
put 0 into winningLength
repeat for each element E in A
get the number of items in E
if it < winningLength then next repeat
if it > winningLength then
put it into winningLength
put empty into winningList
end if
put (char 1 to -2 of E) & cr after winningList
end repeat
put winningList
end mouseUp
 
function sortChars X
get charsToItems(X)
sort items of it
return itemsToChars(it)
end sortChars
 
function charsToItems X
repeat for each char C in X
put C & comma after R
end repeat
return char 1 to -2 of R
end charsToItems
 
function itemsToChars X
replace comma with empty in X
return X
end itemsToChars

Output:

abel,able,bale,bela,elba
elan,lane,lean,lena,neal
evil,levi,live,veil,vile
caret,carte,cater,crate,trace
angel,angle,galen,glean,lange
alger,glare,lager,large,regal

[edit] Ruby

require 'open-uri'
 
anagram = Hash.new {|hash, key| hash[key] = []} # map sorted chars to anagrams
 
open('http://www.puzzlers.org/pub/wordlists/unixdict.txt') do |f|
words = f.read.split
for word in words
anagram[word.split('').sort] << word
end
end
 
count = anagram.values.map {|ana| ana.length}.max
anagram.each_value do |ana|
if ana.length >= count
p ana
end
end

Output:

["evil", "levi", "live", "veil", "vile"]
["abel", "able", "bale", "bela", "elba"]
["elan", "lane", "lean", "lena", "neal"]
["alger", "glare", "lager", "large", "regal"]
["angel", "angle", "galen", "glean", "lange"]
["caret", "carte", "cater", "crate", "trace"]

Translation of: Haskell Works with: Ruby version 1.8.7+

require 'open-uri'
 
anagram = nil
 
open('http://www.puzzlers.org/pub/wordlists/unixdict.txt') do |f|
anagram = f.read.split.group_by {|s| s.each_char.sort}
end
 
count = anagram.each_value.map {|ana| ana.length}.max
anagram.each_value do |ana|
if ana.length >= count
p ana
end
end


[edit] Scala

val lines = scala.io.Source.fromURL("http://www.puzzlers.org/pub/wordlists/unixdict.txt").getLines.map(s=>s.trim())
 
var map = Map[String, Set[String]]() withDefaultValue Set()
def hash(s:String) = new String(s.toList.sort(_<_).toArray)
map = lines.foldLeft(map)((map,s) => map(hash(s)) += s)
 
val max = map.values.foldLeft(0)((a,b) => a.max(b.size))
 
map.values.filter(l => l.size == max).foreach{l=>l.foreach(s=>print(s+" ")); println()}

Output:

glean angel angle galen lange 
elan neal lean lane lena 
regal alger large lager glare 
able abel bela bale elba 
vile levi live evil veil 
caret trace cater carte crate

[edit] Smalltalk

list:= (FillInTheBlank request: 'myMessageBoxTitle') subStrings: String crlf.
dict:= Dictionary new.
list do: [:val|
(dict at: val copy sort ifAbsent: [dict at: val copy sort put: OrderedCollection new])
add: val.
].
sorted:=dict asSortedCollection: [:a :b| a size > b size].

Documentation:

First ask the user for the list.
Then create an empty dictionary (a Map). Which maps strings as keys to OrderedCollections as values.
For each entry in the list add an entry to the OrderedCollection under the key of the sorted string 
(and create a new empty OC if there was no previous entry).
Then create a SortedCollection sorting by comparing the sizes of the OrderedCollections.
The first 6 entries are:
an OrderedCollection('evil' 'levi' 'live' 'veil' 'vile') 
an OrderedCollection('angel' 'angle' 'galen' 'glean' 'lange') 
an OrderedCollection('alger' 'glare' 'lager' 'large' 'regal') 
an OrderedCollection('caret' 'carte' 'cater' 'crate' 'trace') 
an OrderedCollection('abel' 'able' 'bale' 'bela' 'elba') 
an OrderedCollection('elan' 'lane' 'lean' 'lena' 'neal')

[edit] SNOBOL4

Works with: Macro Spitbol

Note: unixdict.txt is passed in locally via STDIN. Newlines must be converted for Win/DOS environment.

*       # Sort letters of word        
define('sortw(str)a,i,j') :(sortw_end)
sortw a = array(size(str))
sw1 i = i + 1; str len(1) . a<i> = :s(sw1)
a = sort(a)
sw2 j = j + 1; sortw = sortw a<j> :s(sw2)f(return)
sortw_end
 
* # Count words in string
define('countw(str)') :(countw_end)
countw str break(' ') span(' ') = :f(return)
countw = countw + 1 :(countw)
countw_end
 
ana = table()
L1 wrd = input :f(L2) ;* unixdict.txt from stdin
sw = sortw(wrd); ana<sw> = ana<sw> wrd ' '
cw = countw(ana<sw>); max = gt(cw,max) cw
i = i + 1; terminal = eq(remdr(i,1000),0) wrd :(L1)
L2 kv = convert(ana,'array')
L3 j = j + 1; key = kv<j,1>; val = kv<j,2> :f(end)
output = eq(countw(val),max) key ': ' val :(L3)
end

Output:

abel: abel able bale bela elba 
aeglr: alger glare lager large regal 
aegln: angel angle galen glean lange 
acert: caret carte cater crate trace 
aeln: elan lane lean lena neal 
eilv: evil levi live veil vile

[edit] Tcl

package require Tcl 8.5
package require http
 
set url http://www.puzzlers.org/pub/wordlists/unixdict.txt
set response [http::geturl $url]
set data [http::data $response]
http::cleanup $response
 
set max 0
array set anagrams {}
 
foreach line [split $data \n] {
foreach word [split $line] {
set anagram [join [lsort [split $word ""]] ""]
lappend anagrams($anagram) $word
set max [::tcl::mathfunc::max $max [llength $anagrams($anagram)]]
}
}
 
foreach key [array names anagrams] {
if {[llength $anagrams($key)] == $max} {
puts $anagrams($key)
}
}

Outputs:

evil levi live veil vile
caret carte cater crate trace
abel able bale bela elba
elan lane lean lena neal
angel angle galen glean lange
alger glare lager large regal

[edit] Ursala

Supplying the input file on the command line during compilation makes its contents accessible as a pre-declared identifier. The algorithm is to group the words together that are made from the same unordered lists of letters, then collect the groups together that have the same number of words in them, and then show the collection associated with the highest number.

#import std
 
#show+
 
anagrams = mat` * leql$^&h eql|=@rK2tFlSS ^(~&,-<&)* unixdict_dot_txt

output:

evil levi live veil vile
caret carte cater crate trace
alger glare lager large regal
elan lane lean lena neal
angel angle galen glean lange
abel able bale bela elba

[edit] Vedit macro language

This implementation first sorts characters of each word using Insertion sort in subroutine SORT_LETTERS.
Then the word list is sorted using built-in Sort function.
Finally, groups of words are analyzed and largest groups are recorded.

The word list is expected to be in the same directory as the script.

File_Open("|(PATH_ONLY)\unixdict.txt")
 
Repeat(ALL) {
Reg_Copy_Block(10, CP, EOL_Pos) // original word
Call("SORT_LETTERS") // sort letters of the word
EOL
IC(' ') Reg_Ins(10) // add the original word at eol
Line(1, ERRBREAK)
}
 
Sort(0, File_Size) // sort list according to anagrams
 
BOF
Search("|F") Search(' ') // first word in the list
Reg_Copy_Block(10, BOL_Pos, CP+1) // reg 10 = sorted anagram word
Reg_Copy_Block(11, CP, EOL_Pos) // reg 11 = list of words in current group
Reg_Empty(12) // reg 12 = list of words in largest groups
Reg_Set(13, "
")
#1 = 1 // words in this group
#2 = 2 // words in largest group found
Repeat(ALL) {
Line(1, ERRBREAK)
if (Match(@10, ADVANCE) == 0) { // same group as previous word?
Reg_Copy_Block(11, CP-1, EOL_Pos, APPEND) // add word to this group
#1++
} else { // different anagram group
Search(" ", ERRBREAK)
if (#1 == #2) { // same size as the largest?
Reg_Set(12, @13, APPEND) // append newline
Reg_Set(12, @11, APPEND) // append word list
}
if (#1 > #2) { // new larger size of group
Reg_Set(12, @11) // replace word list
#2 = #1
}
Reg_Copy_Block(10, BOL_Pos, CP+1)
Reg_Copy_Block(11, CP, EOL_Pos) // first word of new group
#1 = 1
}
}
 
Buf_Quit(OK) // close word list file
Buf_Switch(Buf_Free) // output results in a new edit buffer
Reg_Ins(12) // display all groups of longest anagram words
Return
 
////////////////////////////////////////////////////////////////////
//
// Sort characters in current line using Insertion sort
//
:SORT_LETTERS:
GP(EOL_pos) #9 = Cur_Col-1
for (#1 = 2; #1 <= #9; #1++) {
Goto_Col(#1) #8 = Cur_Char
#2 = #1
while (#2 > 1) {
#7 = Cur_Char(-1)
if (#7 <= #8) { break }
Ins_Char(#7, OVERWRITE)
#2--
Goto_Col(#2)
}
Ins_Char(#8, OVERWRITE)
}
return

Output:

abel able bale bela elba
caret carte cater crate trace
angel angle galen glean lange
alger glare lager large regal
elan lane lean lena neal
evil levi live veil vile
Personal tools
Support