Haskell 如何取消列表展平
我可以轻松地展平嵌套数据结构,但双重操作似乎非常困难(至少对我来说) 给定类型列表Haskell 如何取消列表展平,haskell,Haskell,我可以轻松地展平嵌套数据结构,但双重操作似乎非常困难(至少对我来说) 给定类型列表[(a,b,c)],如何创建嵌套结构,即 unflatten :: (Ord a, Ord b) => [(a,b,c)] -> [(a, [(b, [c])])] 这样每个a只发生一次,同样的(a,b) 我不太清楚为什么我要这么做,因为双重操作非常简单 flatten :: [(a, [(b, [c])])] -> [(a,b,c)] flatten xs = [(a,b,c) | (a,bc
[(a,b,c)]
,如何创建嵌套结构,即
unflatten :: (Ord a, Ord b) => [(a,b,c)] -> [(a, [(b, [c])])]
这样每个a
只发生一次,同样的(a,b)
我不太清楚为什么我要这么做,因为双重操作非常简单
flatten :: [(a, [(b, [c])])] -> [(a,b,c)]
flatten xs = [(a,b,c) | (a,bcs) <- xs, (b,cs) <- bcs, c<-cs]
flatten::[(a,[(b,[c])]->[(a,b,c)]
展平xs=[(a,b,c)|(a,bcs)就我个人而言,我会将数据放入嵌套的映射中。之后,您总是可以将其再次拉出到嵌套的关联列表中
首先,将每个项目转换为一个(小)嵌套映射,列表中有一个元素[c]
:
import qualified Data.Map as M
import Data.List
triplesToMaps :: [(a,b,c)] -> [M.Map a (M.Map b [c])]
triplesToMaps = map (\(a,b,c) -> M.singleton a (M.singleton b [c]))
然后使用unionWith
combineMaps :: (Ord a, Ord b) => [M.Map a (M.Map b [c])] -> M.Map a (M.Map b [c])
combineMaps = foldl' (M.unionWith (M.unionWith (++))) M.empty
然后,如果您愿意,将其带回列表:
flattenToLists :: M.Map a (M.Map b [c]) -> [(a,[(b,[c])])]
flattenToLists = M.assocs . (M.map M.assocs)
例如:
> flattenToLists . combineMaps . triplesToMaps $ [(1,2,3),(1,2,4),(1,3,5),(2,6,8)]
[(1,[(2,[3,4]),(3,[5])]),(2,[(6,[8])])]
实际上,您可能不会plattolists
,因为嵌套映射是更有用的结构
顺便说一句,如果Map
具有“正确”的幺半群结构,那么M.unionWith(M.unionWith(++)
将只是mappend
,整个事情可以是foldMap(\(a,b,c)->M.singleton a(M.singleton b[c])
[已编辑:添加了问题中的双字符]
哦,回到[(a,b,c)]
我想到了两种方法。列表理解和你的一样,但是使用assocs
:
flatten :: M.Map a (M.Map b [c]) -> [(a,b,c)]
flatten m = [(a,b,c) | (a,bcs) <- M.assocs m, (b,cs) <- M.assocs bcs, c <- cs]
就我个人而言,我会将这些数据放入一个嵌套的映射中。之后,您总是可以将其再次拉入嵌套的关联列表中
首先,将每个项目转换为一个(小)嵌套映射,列表中有一个元素[c]
:
import qualified Data.Map as M
import Data.List
triplesToMaps :: [(a,b,c)] -> [M.Map a (M.Map b [c])]
triplesToMaps = map (\(a,b,c) -> M.singleton a (M.singleton b [c]))
然后使用unionWith
combineMaps :: (Ord a, Ord b) => [M.Map a (M.Map b [c])] -> M.Map a (M.Map b [c])
combineMaps = foldl' (M.unionWith (M.unionWith (++))) M.empty
然后,如果您愿意,将其带回列表:
flattenToLists :: M.Map a (M.Map b [c]) -> [(a,[(b,[c])])]
flattenToLists = M.assocs . (M.map M.assocs)
例如:
> flattenToLists . combineMaps . triplesToMaps $ [(1,2,3),(1,2,4),(1,3,5),(2,6,8)]
[(1,[(2,[3,4]),(3,[5])]),(2,[(6,[8])])]
实际上,您可能不会plattolists
,因为嵌套映射是更有用的结构
顺便说一句,如果Map
具有“正确”的幺半群结构,那么M.unionWith(M.unionWith(++)
将只是mappend
,整个事情可以是foldMap(\(a,b,c)->M.singleton a(M.singleton b[c])
[已编辑:添加了问题中的双字符]
哦,回到[(a,b,c)]
我想到了两种方法。列表理解和你的一样,但是使用assocs
:
flatten :: M.Map a (M.Map b [c]) -> [(a,b,c)]
flatten m = [(a,b,c) | (a,bcs) <- M.assocs m, (b,cs) <- M.assocs bcs, c <- cs]
按照ErikR的建议,出现了一种模式,即如何将其扩展到越来越长的元组
-- construct some raw material
l a i = map ((a ++) . show) [1..i]
l4 = [(a,b,c,d) | d<-l "d" 3, c <- l "c" 3, b<-l "b" 3, a<-l "a" 2 ]
grp2 :: Ord a => [(a,b)] -> [(a,[b])]
grp2 xs = do
a <- (nub . sort . map fst) xs
let bs = [b' | (a',b') <- xs, a'==a]
return (a,bs)
grp3 :: (Ord a, Ord b) => [(a,b,c)] -> [(a,[(b,[c])])]
grp3 ys = do
(a, bcs) <- grp2 (map split3 ys)
return (a, grp2 bcs)
where
split3 (a,b,c) = (a,(b,c))
grp4 :: (Ord a, Ord b, Ord c) => [(a,b,c,d)] -> [(a,[(b,[(c,[d])])])]
grp4 zs = do
(a, bcds) <- grp2 (map split4 zs)
return (a, grp3 bcds)
where
split4 (a,b,c,d) = (a,(b,c,d))
印刷品
[ ( "a1"
, [ ( "b1"
, [ ( "c1" , [ "d1" , "d2" , "d3" ] )
, ( "c2" , [ "d1" , "d2" , "d3" ] )
, ( "c3" , [ "d1" , "d2" , "d3" ] )
]
)
, ( "b2"
, [ ( "c1" , [ "d1" , "d2" , "d3" ] )
, ( "c2" , [ "d1" , "d2" , "d3" ] )
, ( "c3" , [ "d1" , "d2" , "d3" ] )
]
)
, ( "b3"
, [ ( "c1" , [ "d1" , "d2" , "d3" ] )
, ( "c2" , [ "d1" , "d2" , "d3" ] )
, ( "c3" , [ "d1" , "d2" , "d3" ] )
]
)
]
)
, ( "a2"
, [ ( "b1"
, [ ( "c1" , [ "d1" , "d2" , "d3" ] )
, ( "c2" , [ "d1" , "d2" , "d3" ] )
, ( "c3" , [ "d1" , "d2" , "d3" ] )
]
)
, ( "b2"
, [ ( "c1" , [ "d1" , "d2" , "d3" ] )
, ( "c2" , [ "d1" , "d2" , "d3" ] )
, ( "c3" , [ "d1" , "d2" , "d3" ] )
]
)
, ( "b3"
, [ ( "c1" , [ "d1" , "d2" , "d3" ] )
, ( "c2" , [ "d1" , "d2" , "d3" ] )
, ( "c3" , [ "d1" , "d2" , "d3" ] )
]
)
]
)
]
按照ErikR的建议,出现了一种模式,即如何将其扩展到越来越长的元组
-- construct some raw material
l a i = map ((a ++) . show) [1..i]
l4 = [(a,b,c,d) | d<-l "d" 3, c <- l "c" 3, b<-l "b" 3, a<-l "a" 2 ]
grp2 :: Ord a => [(a,b)] -> [(a,[b])]
grp2 xs = do
a <- (nub . sort . map fst) xs
let bs = [b' | (a',b') <- xs, a'==a]
return (a,bs)
grp3 :: (Ord a, Ord b) => [(a,b,c)] -> [(a,[(b,[c])])]
grp3 ys = do
(a, bcs) <- grp2 (map split3 ys)
return (a, grp2 bcs)
where
split3 (a,b,c) = (a,(b,c))
grp4 :: (Ord a, Ord b, Ord c) => [(a,b,c,d)] -> [(a,[(b,[(c,[d])])])]
grp4 zs = do
(a, bcds) <- grp2 (map split4 zs)
return (a, grp3 bcds)
where
split4 (a,b,c,d) = (a,(b,c,d))
印刷品
[ ( "a1"
, [ ( "b1"
, [ ( "c1" , [ "d1" , "d2" , "d3" ] )
, ( "c2" , [ "d1" , "d2" , "d3" ] )
, ( "c3" , [ "d1" , "d2" , "d3" ] )
]
)
, ( "b2"
, [ ( "c1" , [ "d1" , "d2" , "d3" ] )
, ( "c2" , [ "d1" , "d2" , "d3" ] )
, ( "c3" , [ "d1" , "d2" , "d3" ] )
]
)
, ( "b3"
, [ ( "c1" , [ "d1" , "d2" , "d3" ] )
, ( "c2" , [ "d1" , "d2" , "d3" ] )
, ( "c3" , [ "d1" , "d2" , "d3" ] )
]
)
]
)
, ( "a2"
, [ ( "b1"
, [ ( "c1" , [ "d1" , "d2" , "d3" ] )
, ( "c2" , [ "d1" , "d2" , "d3" ] )
, ( "c3" , [ "d1" , "d2" , "d3" ] )
]
)
, ( "b2"
, [ ( "c1" , [ "d1" , "d2" , "d3" ] )
, ( "c2" , [ "d1" , "d2" , "d3" ] )
, ( "c3" , [ "d1" , "d2" , "d3" ] )
]
)
, ( "b3"
, [ ( "c1" , [ "d1" , "d2" , "d3" ] )
, ( "c2" , [ "d1" , "d2" , "d3" ] )
, ( "c3" , [ "d1" , "d2" , "d3" ] )
]
)
]
)
]
如果您对a、b、c没有限制,这是不可能的,但您应该看看groupBy
您是否可以编写或提供更简单的分组函数,即[(a、b)]->[(a、[b])]
?@epsilonhalbe我添加了约束。不过我认为我不需要对c进行约束。如果你没有约束-对a,b,c这是不可能的,但你应该看看groupBy
你能写一个或你有一个更简单的groupBy函数吗,即[(a,b)]->[(a,[b])]
?@epsilonhalbe我添加了约束。不过我认为我不需要c上的约束。