如何使用过滤器查找文本中的相邻单词



作为借口:在此之前,我编写了一个函数,用于计算一对单词在文本中出现的次数,该函数计算整个文本中的每一对单词。像这样:

pairCounter =  map (x -> (head x,length x)). groupTuples . sort

此函数返回:[((String, String), Int)]第一个/第二个字符串是该对中的单词1/2,Int是可以找到的次数,或者";"计数";如果你愿意的话。

我现在想做的是创建一个只返回"0"的函数;邻居";对任何给定的单词。例如:

neighbours [(("red","car"),2),(("house","red"),1)] "red"

应返回CCD_ 2或对该列表进行某种重新排序。

所以基本上;我们已经建立了任何给定单词的所有对,但现在我只想挑出这个单词的邻居和它的频率。

到目前为止,我已经考虑过以这种方式使用过滤器:

filter ((x, y) -> x /= c || y /= c)
--^(I have no idea if this is syntax correct but it is just to give myself an idea where to start)

然而,我发现很难想出一种方法来使用过滤器,同时也包括我的邻居的计数,我的Int论点是。

一种非常惯用的方法是通过列表理解:

neighbours :: Eq a => [((a, a), b)] -> a -> [(a, b)]
neighbours items query =
[ (neighbor, count)
| ((s1, s2), count) <- items
, (self, neighbor) <- [(s1, s2), (s2, s1)]
, self == query
]

事实上,我可能会把参数放在另一个顺序,以匹配现有库中使用的约定,并缩短名称,使其轻松地放在一行:

neighbours :: Eq a => a -> [((a, a), b)] -> [(a, b)]
neighbours x xs = [(x4, n) | ((x1, x2), n) <- xs, (x3, x4) <- [(x1, x2), (x2, x1)], x3 == x]

我怀疑你不关心顺序的部分会出现在你代码的其他部分,所以另外我会考虑拆分一个对称的部分。如果稍后您决定对两个订单中出现的对进行规范化并对其计数进行求和或诸如此类的事情,这也会很有帮助,因为您只需要更改一个位置即可将更新传播给所有消费者。

-- (s)ource, (t)arget, (u)ndirected edge, (w)eight, (w)eighted edge(s)
undirected :: [((a, a), b)] -> [((a, a), b)]
undirected ws = [(u, w) | ((s, t), w) <- ws, u <- [(s, t), (t, s)]]
neighbours :: Eq a => a -> [((a, a), b)] -> [(a, b)]
neighbours x xs = [(t, w) | ((s, t), w) <- undirected xs, s == x]

或者,您可以决定从一开始就使图形无向。

import qualified Data.Map as M
-- export UPair the type but not UPair the constructor
data UPair a = UPair a a
deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)
-- this is strict. can also make a lazy variant
upair :: Ord a => a -> a -> UPair a
upair a a' = if a < a' then UPair a a' else UPair a' a
pairCounter :: [a] -> M.Map (UPair a) Int
pairCounter as = M.fromListWith (+) $ zipWith (a a' -> (upair a a', 1)) as (tail as)
因此,对于给定的单词c,您应该保留第一个String或第二个String等于c的项。我们应该使用((s1, s2), v)作为模式,因为外部2元组的元素是Strings的2元组作为第一项,Int作为第二项。

我们可以使用concatMap :: Foldable t => (a -> [b]) -> t a -> [b],如果s1匹配,则使用返回[(s2, v)]的函数;如果s2匹配,则返回[(s1, v)];如果两个元素都不匹配,则可以使用空列表:

因此,我们使用进行过滤

neighbors :: (Foldable f, Eq a) -> f ((a, a), b) -> a -> [(a, b)]
neighbors items query = concatMap f items
where f ((s1, s2), v)
| query == s1= [(s2, v)]
| query == s2= [(s1, v)]
| otherwise = []

最新更新