案例转换大字典词集

时间:2016-09-02 18:35:30

标签: haskell optimization data-structures

我正在尝试匹配字典中的单词,不区分大小写。我的初步方法 看起来像这样:

  1. 读dict;将所有单词转换为小写,存储在set中。
  2. 检查
  3. 中的会员资格的新单词

    有更好(更有效)的方法来实现这一目标吗?我是Haskell的新手。

    import System.IO
    import Data.Text (toLower, pack, unpack)
    import Data.Set (fromList, member)
    
    main = do
      let path = "/usr/share/dict/american-english"
      h <- openFile path ReadMode
      hSetEncoding h utf8
      contents <- hGetContents h
      let mySet = (fromList . map (unpack . toLower . pack) . lines) contents
      putStrLn $ show $ member "acadia" mySet
    

3 个答案:

答案 0 :(得分:7)

我只是直接使用Text而不是转换为/来自Strings。

Data.Text.IO包含hGetContentsreadFile等版本,用于从文件中读取文本,Data.Text包含lines文本。

{-# LANGUAGE OverloadedStrings #-}
import System.IO
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Set as S

main = do
  let path = "/usr/share/dict/american-english"
  h <- openFile path ReadMode
  hSetEncoding h utf8
  contents <- T.hGetContents h
  let mySet = (S.fromList . map T.toLower . T.lines) contents
  putStrLn $ show $ S.member "acadia" mySet

通过使用T.tolowerT.lines,我们避免显式打包/解包。

mySet现在是一组Text值而不是字符串。通过使用 OverloadedStrings pragma将解释文字"acadia" 作为文本值。

答案 1 :(得分:2)

是的,你的建议是合理的。一些评论,主要与主要问题无关:

  1. 将自己限制为仅使用Text而不是String会更有效。
  2. 首选toCaseFold功能toLower,这种情况更合适。

答案 2 :(得分:1)

即使您发现我的第一个回答有帮助,让我提出另一种方法......

我写的一个boggle求解器只是在整个字典中读取一个ByteString,并且查找单词在该ByteString上执行二进制搜索。

字典必须已按排序顺序排列并标准化为小写,但通常这不是问题,因为字典是静态的 并提前知道。

当然,当您在执行二进制搜索时计算(lo+hi)/2时,您可能会在单词的中间位置,因此您只需备份到当前单词的开头。

这样做的主要优点是加载字典非常快,而且内存效率很高。此外,搜索算法具有良好的内存局部性。我没有测量过,但如果创建一个Data.Set将比原始数据的大小增加一倍,我不会感到惊讶。

代码可在此处找到:https://github.com/erantapaa/hoggle