Haskell中有zip
Set
的方式,而不必先将其转换为List
吗?
我想要一个从给定边缘数据创建一组顶点的函数。顶点基本上是一对索引及其数据。
data Vertex a = Vertex { idx::Int, cont::a }
toVertexSet :: S.Set String -> S.Set (Vertex String)
toVertexSet = undefined
toStringSet:: [(String, String, Int)] -> S.Set String
toStringSet = foldl insertToSet S.empty where
insertToSet set (vfrom, vto, _) =
case (S.member vfrom set, S.member vto set) of
(True, True) -> set
(True, False) -> S.insert vto set
(False, True) -> S.insert vfrom set
(False, False) -> S.insert vto (S.insert vfrom set)
基本上我希望toVertexSet
将每个String
与唯一Int
配对作为索引,从1开始排列到集合的大小,将其转换为一组顶点。有没有更好的方法来做到这一点,而不必先将集合转换回List?
答案 0 :(得分:6)
集合是可折叠的,因此您可以使用折叠:
import Data.Foldable (foldl')
data Vertex a = Vertex { idx::Int, cont::a } deriving (Eq, Ord)
toVertexSet :: S.Set String -> S.Set (Vertex String)
toVertexSet = snd . foldl' (\(i, vs) s -> (i+1, S.insert Vertex { idx = i, cont = s } vs)) (1, S.empty)
答案 1 :(得分:2)
您不需要zip
来实现这一点,我目前的解决方案是根据其内容在Eq
上派生Vertex
,以便它可以直接存储在Set中,并且使用带有最后插入索引的辅助函数作为附加参数。不过,我失去了优雅的褶皱。
instance (Eq a) => Eq (Vertex a) where
v1 == v2 = cont v1 == cont v2
instance (Eq a, Ord a) => Ord (Vertex a) where
v1 `compare` v2 = cont v1 `compare` cont v2
toVertexSet:: [(String, String, Int)] -> S.Set (Vertex String)
toVertexSet = insertToSet 0 S.empty where
insertToSet _ set [] = set
insertToSet ix set ((vfrom, vto, _):rest) =
let newVertex = Vertex ix
nvfrom = newVertex vfrom
nvto = newVertex vto
incrOne (Vertex i m) = Vertex (i + 1) m
in case (S.member nvfrom set, S.member nvto set) of
(True, True) -> insertToSet ix set rest
(True, False) -> insertToSet (ix + 1) (S.insert nvto set) rest
(False, True) -> insertToSet (ix + 1) (S.insert nvfrom set) rest
(False, False) -> insertToSet (ix + 2) (S.insert (incrOne nvfrom)
(S.insert nvto set)) rest