Anagrams: Difference between revisions
Content added Content deleted
(Updated the Crystal code to avoid Nil reference error) |
(→{{header|JavaScript}}: Added an ES6 variant for JavaScript for Automation (macOS – JXA)) |
||
Line 3,586: | Line 3,586: | ||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
||
===ES5=== |
|||
{{Works with|Node.js}} |
{{Works with|Node.js}} |
||
<lang javascript>var fs = require('fs'); |
<lang javascript>var fs = require('fs'); |
||
Line 3,619: | Line 3,620: | ||
[ 'evil', 'levi', 'live', 'veil', 'vile' ]</pre> |
[ 'evil', 'levi', 'live', 'veil', 'vile' ]</pre> |
||
Alternative using reduce: |
|||
<lang javascript>var fs = require('fs'); |
<lang javascript>var fs = require('fs'); |
||
var dictionary = fs.readFileSync('unixdict.txt', 'UTF-8').split('\n'); |
var dictionary = fs.readFileSync('unixdict.txt', 'UTF-8').split('\n'); |
||
Line 3,642: | Line 3,643: | ||
console.log(sortedDict[key].join(' ')); |
console.log(sortedDict[key].join(' ')); |
||
});</lang> |
});</lang> |
||
===ES6=== |
|||
Using JavaScript for Automation |
|||
(A JavaScriptCore interpreter on macOS with an Automation library). |
|||
<lang javascript>(() => { |
|||
'use strict'; |
|||
// largestAnagramGroups :: FilePath -> Either String [[String]] |
|||
const largestAnagramGroups = fp => |
|||
either(msg => msg)(strLexicon => { |
|||
const |
|||
groups = sortBy(flip(comparing(length)))( |
|||
groupBy(on(eq)(fst))( |
|||
sortBy(comparing(fst))( |
|||
strLexicon |
|||
.split(/[\r\n]/) |
|||
.map(w => [w.split('').sort().join(''), w]) |
|||
) |
|||
) |
|||
), |
|||
maxSize = groups[0].length; |
|||
return map(map(snd))( |
|||
takeWhile(x => maxSize === x.length)( |
|||
groups |
|||
) |
|||
) |
|||
})(readFileLR(fp)); |
|||
// ------------------------TEST------------------------ |
|||
const main = () => |
|||
console.log(JSON.stringify( |
|||
largestAnagramGroups('unixdict.txt'), |
|||
null, 2 |
|||
)) |
|||
// -----------------GENERIC FUNCTIONS------------------ |
|||
// Left :: a -> Either a b |
|||
const Left = x => ({ |
|||
type: 'Either', |
|||
Left: x |
|||
}); |
|||
// Right :: b -> Either a b |
|||
const Right = x => ({ |
|||
type: 'Either', |
|||
Right: x |
|||
}); |
|||
// Tuple (,) :: a -> b -> (a, b) |
|||
const Tuple = a => |
|||
b => ({ |
|||
type: 'Tuple', |
|||
'0': a, |
|||
'1': b, |
|||
length: 2 |
|||
}); |
|||
// comparing :: (a -> b) -> (a -> a -> Ordering) |
|||
const comparing = f => |
|||
x => y => { |
|||
const |
|||
a = f(x), |
|||
b = f(y); |
|||
return a < b ? -1 : (a > b ? 1 : 0); |
|||
}; |
|||
// either :: (a -> c) -> (b -> c) -> Either a b -> c |
|||
const either = fl => |
|||
fr => e => 'Either' === e.type ? ( |
|||
undefined !== e.Left ? ( |
|||
fl(e.Left) |
|||
) : fr(e.Right) |
|||
) : undefined; |
|||
// eq (==) :: Eq a => a -> a -> Bool |
|||
const eq = a => |
|||
// True when a and b are equivalent. |
|||
b => a === b |
|||
// flip :: (a -> b -> c) -> b -> a -> c |
|||
const flip = f => |
|||
1 < f.length ? ( |
|||
(a, b) => f(b, a) |
|||
) : (x => y => f(y)(x)); |
|||
// fst :: (a, b) -> a |
|||
const fst = tpl => |
|||
// First member of a pair. |
|||
tpl[0]; |
|||
// groupBy :: (a -> a -> Bool) -> [a] -> [[a]] |
|||
const groupBy = fEq => xs => |
|||
// // Typical usage: groupBy(on(eq)(f), xs) |
|||
0 < xs.length ? (() => { |
|||
const |
|||
tpl = xs.slice(1).reduce( |
|||
(gw, x) => { |
|||
const |
|||
gps = gw[0], |
|||
wkg = gw[1]; |
|||
return fEq(wkg[0])(x) ? ( |
|||
Tuple(gps)(wkg.concat([x])) |
|||
) : Tuple(gps.concat([wkg]))([x]); |
|||
}, |
|||
Tuple([])([xs[0]]) |
|||
); |
|||
return tpl[0].concat([tpl[1]]) |
|||
})() : []; |
|||
// length :: [a] -> Int |
|||
const length = xs => xs.length |
|||
// map :: (a -> b) -> [a] -> [b] |
|||
const map = f => |
|||
// The list obtained by applying f |
|||
// to each element of xs. |
|||
// (The image of xs under f). |
|||
xs => xs.map(f); |
|||
// on :: (b -> b -> c) -> (a -> b) -> a -> a -> c |
|||
const on = f => |
|||
// e.g. sortBy(on(compare,length), xs) |
|||
g => a => b => f(g(a))(g(b)); |
|||
// readFileLR :: FilePath -> Either String IO String |
|||
const readFileLR = fp => { |
|||
const |
|||
e = $(), |
|||
ns = $.NSString |
|||
.stringWithContentsOfFileEncodingError( |
|||
$(fp).stringByStandardizingPath, |
|||
$.NSUTF8StringEncoding, |
|||
e |
|||
); |
|||
return ns.isNil() ? ( |
|||
Left(ObjC.unwrap(e.localizedDescription)) |
|||
) : Right(ObjC.unwrap(ns)); |
|||
}; |
|||
// snd :: (a, b) -> b |
|||
const snd = tpl => tpl[1]; |
|||
// sortBy :: (a -> a -> Ordering) -> [a] -> [a] |
|||
const sortBy = f => |
|||
xs => xs.slice() |
|||
.sort((a, b) => f(a)(b)); |
|||
// takeWhile :: (a -> Bool) -> [a] -> [a] |
|||
// takeWhile :: (Char -> Bool) -> String -> String |
|||
const takeWhile = p => |
|||
xs => { |
|||
const lng = xs.length; |
|||
return 0 < lng ? xs.slice( |
|||
0, |
|||
until(i => lng === i || !p(xs[i]))( |
|||
i => 1 + i |
|||
)(0) |
|||
) : []; |
|||
}; |
|||
// until :: (a -> Bool) -> (a -> a) -> a -> a |
|||
const until = p => f => x => { |
|||
let v = x; |
|||
while (!p(v)) v = f(v); |
|||
return v; |
|||
}; |
|||
// MAIN --- |
|||
return main(); |
|||
})();</lang> |
|||
{{Out}} |
|||
<pre>[ |
|||
[ |
|||
"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" |
|||
] |
|||
]</pre> |
|||
=={{header|jq}}== |
=={{header|jq}}== |