比较和计算与Haskell的字符串相关性

时间:2012-12-20 19:24:58

标签: haskell comparison classification string-comparison

我正在研究一个非常复杂的(至少对我很复杂)函数,我想用它来计算列表中的单词与数据库中的单词对应的次数。

使用随机单词的示例:

let input = [("InputName", ["dog", "cat", "cat"...]), ...]
let database = ["dog", "cat", "badger"...]

经过几个小时的心理体操后,我想出了这个几乎有效的可怕功能。我已经简化了它,所以在这个例子的上下文中它是有意义的:

findMatches input database = [ (snd x, wordCount (snd x)) | x <- input ]
    where
        wordCount ys = sum[ if y `elem` database then 1 else 0 | y <- ys ]

我的目标,我的希望,我的愿望是输出:

[("dog", 1), ("cat", 2), ("badger", 0)]

任何有正确方向的建议或推动都会受到赞赏。

修改

我终于做了一个有效的功能。 catWordCount计算数据库条目在输入中出现的次数。我正在使用fold进行更好的实现。

let input = words "5 4 10 0 1 9 1"
let database = [("C1", words "1 2 3 4 5"), ("C2", words "6 7 8 9 10")]

catwordCount input database

catWordCount fs zs = [ (fst f, inputSearch (snd f)) | f <- fs ]
    where
        inputSearch gs = [ (g, wordCount [g]) | g <- gs ]
        wordCount hs = sum[ if h == z then 1 else 0 | h <- hs, z <- zs ]

输出:

(["C1", [("1",2),("2",0),("3",0),("4",1),("5",1)])
(["C2", [("6",0),("7",0),("8",0),("9",1),("10",1)])

2 个答案:

答案 0 :(得分:3)

您可以保留为每个项目更新的Map个计数。由于您不希望在输入列表中包含不在数据库中的项目,如果我理解正确,

alter :: Ord k => (Maybe a -> Maybe a) -> k -> Map k a -> Map k a

是一个很好的方法。查找提供的密钥k,如果它存在,则更新函数的参数将为Just value,否则为Nothing。如果更新功能的结果为Nothing,则密钥将从Map中删除(如果结果不存在,则不添加),如果结果为Just something,则密钥将与更改后的something中的Map相关联。

所以你开始用Map将每个项目映射到0,

m0 :: Map String Int
m0 = fromList $ zip database (repeat 0)

要更新,如果项目在database,您希望增加计数,否则不会更改任何内容,

incr :: Maybe Int -> Maybe Int
incr (Just n) = Just (n+1)
incr Nothing  = Nothing

或更短,incr = fmap (+1)使用Functor的{​​{1}}个实例。

然后生成的地图就是

Maybe

如果您想要列表而不是finalMap :: Map String Int finalMap = foldl (flip $ alter incr) m0 $ snd input ,只需在Map上致电assocstoList

答案 1 :(得分:0)

这可能不是你想要的,但试试这个:

import Data.List

countMatches :: [(String, [String])] -> [(String, Int)]
countMatches = map (\l -> (head l, length l)) . group . sort . concat . map snd

希望功能组合不会太混乱。我会一步一步地去看看。假设您使用输入

运行此功能
[("", ["a", "b"]), ("", ["b", "c", "x", "a"]), ("", ["y", "b", "z"])]

map snd之后

[["a", "b"], ["b", "c", "x", "a"], ["y", "b", "z"]]

concat之后,

["a", "b", "b", "c", "x", "a", "y", "b", "z"]

sort之后,

["a", "a", "b", "b", "b", "c", "x", "y", "z"]

group之后,

[["a", "a"], ["b", "b", "b"], ["c"], ["x"], ["y"], ["z"]]

最后map (\l -> (head l, length l))生成

[("a", 2), ("b", 3), ("c", 1), ("x", 1), ("y", 1), ("z", 1)]