我是Haskell的新手并尝试制作拼字游戏解算器。它接收您当前拥有的字母,查找它们的所有排列并过滤掉那些字典单词。代码非常简单:
import Data.List
main = do
dict <- readFile "words"
letters <- getLine
let dictWords = words dict
let perms = permutations letters
print [x | x <- perms, x `elem` dictWords]
然而,与我使用Python的非常相似的实现相比,它的速度非常慢。我有什么基本的错误吗?
*编辑:这是我的Python代码:
from itertools import permutations
letters = raw_input("please enter your letters (without spaces): ")
d = open('words')
dictionary = [line.rstrip('\n') for line in d.readlines()]
d.close()
perms = ["".join(p) for p in permutations(letters)]
validWords = []
for p in perms:
if p in dictionary: validWords.append(p)
for validWord in validWords:
print validWord
我没有准确地计算它们,但大致感觉Python实现的速度是Haskell的2倍。也许我不应该说Haskell代码是非常慢的#34;相比之下,但由于Haskell是静态类型的,我想我只是认为它应该更快,而且根本不比Python慢。
答案 0 :(得分:7)
我是Haskell的新手,并尝试制作拼字游戏解算器。
通过使用更好的算法,您可以大大改善事物。
如果你这样做,而不是测试输入字母的每个排列 首先对它们进行排序,你只能进行一次字典查找 所有可能形成的词(anagrams) 他们(使用所有这些)。
这是将该字典创建为Data.Map的代码。 创建地图有一个启动成本,但之后 第一个查询后续查找非常快。
import Data.List
import qualified Data.Map.Strict as Map
import Control.Monad
import System.IO
main = do
contents <- readFile "words"
let pairs = [ (sort w, [w]) | w <- words contents ]
dict = foldl' (\m (k,v) -> Map.insertWith (++) k v m) Map.empty pairs
-- dict = foldr (\(k,v) m -> Map.insertWith (++) k v m) Map.empty pairs
forever $ do
putStr "Enter letters: " >> hFlush stdout
letters <- getLine
case Map.lookup (sort letters) dict of
Nothing -> putStrLn "No words."
Just ws -> putStrLn $ "Words: " ++ show ws
236K字(2.5 MB)的word文件的映射创建时间约为4-5秒。使用ByteStrings或Text代替字符串可能会提高性能。
尝试一些好的字母组合:
steer rat tuna lapse groan neat
注意:使用GHC 7.10.2我发现此代码执行了最好的,而不用编译-O2。
答案 1 :(得分:5)
检查x
是dictWords
的元素是否可能非常慢。我假设您的类似python实现将dictWords
存储在一个集合或排序的向量中(在后一种情况下使用二进制搜索)?好像你可能想在这里做同样的事情。
使用this word list和下面的代码,Python版本在大约30秒内运行,Haskell版本需要1.5分钟。所以Haskell速度较慢(也许是因为它使用了链接列表,所有事情都相同,迭代速度较慢),但是我不会把它称之为#34;速度非常慢&#34;与Python相比。切换为在任一版本中使用集合可将时间减少到1秒以下。
from itertools import permutations
f = open('twl06.txt')
words = f.read().split()
print [''.join(p) for p in permutations('apricot') if ''.join(p) in words]
这是基于集合的Haskell代码:
import Data.Set
import Data.List
main = do
dict <- readFile "twl06.txt"
let letters = "apricot"
let dictWords = Data.Set.fromList $ words dict
let perms = permutations letters
print [x | x <- perms, member x dictWords]