比较两个排序的列表
Compare two List sorted
我有这个编解码器,但是它没有显示重复的元素,为什么?
cosinesim :: Ord a => [(a,Float)] -> [(a,Float)] -> [(a,Float,Float)]
cosinesim a b = go a b
where
go [] b = map (\l -> (fst l, 0, snd l)) b
go a [] = map (\l -> (fst l, snd l, 0)) a
go a@((x,n):t) b@((y,m):r) = case compare x y of
LT -> (x,n,0) : go t b
EQ -> (x,n,m) : go t r
GT -> (y,0,m) : go a r
输入:已排序的两个列表。
列表 1= [(["variety"], 4.50),(["vegetable"], 3.50),(["velvet"], 2.50)]
列表 2=[(["variety"], 4.50),(["ve"], 3.50),(["velvet"], 2.50)]
输出:
[(["variety"], 4.50, 4.50 ), (["vegetable"], 3.50, 0), (["velvet"], 2.50 2.50) ,(["ve"], 0, 3.50)]
我的问题是因为只显示两个列表中重复的元素,因为我想要的是所有元素都出现。
由于您想组合两个列表的元素,因此我建议使用 Data.Map
中的 Map
来保持键的唯一性。然后,您可以使用 union
、unionWith
或 unionWithKey
组合两个地图。不过,第二个在这里会更有用。由于您还想仅使用 0
来指示值何时来自第一个或第二个列表,因此最好有一个明确表示该值的数据类型:
import qualified Data.Map as M
data Those a b
= This a -- Only left
| Those a b -- Both
| That b -- Only right
deriving (Eq, Show)
this :: a -> Those a b -> a
this def (This a) = a
this def (Those a b) = a
this def _ = def
that :: b -> Those a b -> b
that def (That b) = b
that def (Those a b) = b
that def _ = def
-- Give this a better name than Items
type Items k = M.Map k (Those Float Float)
这只是设置了一些我们稍后会用到的类型和工具。 Those
类型表示左、右或两者,而 this
和 that
组合器帮助我们轻松地从中提取值,就像 [=22] 中的 maybe
组合器一样=].
listToLeftItems :: Ord a => [(a, Float)] -> Items a
listToLeftItems = M.fromList . map (fmap This)
listToRightItems :: Ord a => [(a, Float)] -> Items a
listToRightItems = M.fromList . map (fmap That)
cosinesim :: Ord a => [(a, Float)] -> [(a, Float)] -> [(a, Float, Float)]
cosinesim left right
= map (\(key, those) -> (key, this 0 those, that 0 those))
$ M.toList
$ M.unionWith go (listToLeftItems left)
(listToRightItems right)
where
go leftVal rightVal = case (leftVal, rightVal) of
(This a, That b) -> Those a b
(x, y) -> y -- We know we won't have any other combinations,
-- this just keeps the compiler from throwing a warning
listToLeftItems
只是将 This
应用于列表中的每个 Float
,然后将其转换为 Map
,对于 listToRightItems
也是如此。现在你的函数只是将输入列表转换为 Map
s,使用 go
联合它们(我认为这很容易理解),转换回列表,然后将 (a, Those Float Float)
展平至 (a, Float, Float)
。它会为您提供所需的结果,但顺序不同。如果重要的话,您可以以此为基础按照您想要的顺序获取它。
我有这个编解码器,但是它没有显示重复的元素,为什么?
cosinesim :: Ord a => [(a,Float)] -> [(a,Float)] -> [(a,Float,Float)]
cosinesim a b = go a b
where
go [] b = map (\l -> (fst l, 0, snd l)) b
go a [] = map (\l -> (fst l, snd l, 0)) a
go a@((x,n):t) b@((y,m):r) = case compare x y of
LT -> (x,n,0) : go t b
EQ -> (x,n,m) : go t r
GT -> (y,0,m) : go a r
输入:已排序的两个列表。
列表 1= [(["variety"], 4.50),(["vegetable"], 3.50),(["velvet"], 2.50)]
列表 2=[(["variety"], 4.50),(["ve"], 3.50),(["velvet"], 2.50)]
输出:
[(["variety"], 4.50, 4.50 ), (["vegetable"], 3.50, 0), (["velvet"], 2.50 2.50) ,(["ve"], 0, 3.50)]
我的问题是因为只显示两个列表中重复的元素,因为我想要的是所有元素都出现。
由于您想组合两个列表的元素,因此我建议使用 Data.Map
中的 Map
来保持键的唯一性。然后,您可以使用 union
、unionWith
或 unionWithKey
组合两个地图。不过,第二个在这里会更有用。由于您还想仅使用 0
来指示值何时来自第一个或第二个列表,因此最好有一个明确表示该值的数据类型:
import qualified Data.Map as M
data Those a b
= This a -- Only left
| Those a b -- Both
| That b -- Only right
deriving (Eq, Show)
this :: a -> Those a b -> a
this def (This a) = a
this def (Those a b) = a
this def _ = def
that :: b -> Those a b -> b
that def (That b) = b
that def (Those a b) = b
that def _ = def
-- Give this a better name than Items
type Items k = M.Map k (Those Float Float)
这只是设置了一些我们稍后会用到的类型和工具。 Those
类型表示左、右或两者,而 this
和 that
组合器帮助我们轻松地从中提取值,就像 [=22] 中的 maybe
组合器一样=].
listToLeftItems :: Ord a => [(a, Float)] -> Items a
listToLeftItems = M.fromList . map (fmap This)
listToRightItems :: Ord a => [(a, Float)] -> Items a
listToRightItems = M.fromList . map (fmap That)
cosinesim :: Ord a => [(a, Float)] -> [(a, Float)] -> [(a, Float, Float)]
cosinesim left right
= map (\(key, those) -> (key, this 0 those, that 0 those))
$ M.toList
$ M.unionWith go (listToLeftItems left)
(listToRightItems right)
where
go leftVal rightVal = case (leftVal, rightVal) of
(This a, That b) -> Those a b
(x, y) -> y -- We know we won't have any other combinations,
-- this just keeps the compiler from throwing a warning
listToLeftItems
只是将 This
应用于列表中的每个 Float
,然后将其转换为 Map
,对于 listToRightItems
也是如此。现在你的函数只是将输入列表转换为 Map
s,使用 go
联合它们(我认为这很容易理解),转换回列表,然后将 (a, Those Float Float)
展平至 (a, Float, Float)
。它会为您提供所需的结果,但顺序不同。如果重要的话,您可以以此为基础按照您想要的顺序获取它。