在Haskell的列表中连接元组的第二个元素

时间:2016-03-30 05:32:07

标签: haskell tuples concatenation

我有一个这样的清单:

[(1,[2]), (1,[3]), (1,[4]), (2,[1]), (2,[2]), (3,[1])]

我想要的是一个以列表中的第一个元素开头的函数,如果它在列表中找到了与元组类似(fst)的任何其他元素,那么它将找到的元素的(snd)连接到第一个元素的(snd)。在上面显示的示例中,最终结果将是以下列表:

[(1,[2,3,4]), (2,[1,2]), (3,[1])]

我尝试了很多选项却没有成功。有什么建议?

由于

3 个答案:

答案 0 :(得分:2)

import Data.List (groupBy)
import Data.Function (on)
import Control.Arrow ((***))

f  = map ((head *** concat) . unzip) . groupBy ((==) `on` fst)

> let l =  [(1,[2]), (1,[3]), (1,[4]), (2,[1]), (2,[2]), (3,[1])]

> groupBy ((==) `on` fst) l
[[(1,[2]),(1,[3]),(1,[4])],[(2,[1]),(2,[2])],[(3,[1])]]

> map unzip $ groupBy ((==) `on` fst) l
[([1,1,1],[[2],[3],[4]]),([2,2],[[1],[2]]),([3],[[1]])]

您可以使用Control.Arrow中的(***)来操作元组

> (pred *** succ) (4,5)
(3,6)

> let f  = map ((head *** concat) . unzip) . groupBy ((==) `on` fst) 
> f l
[(1,[2,3,4]),(2,[1,2]),(3,[1])]

答案 1 :(得分:1)

Prelude> :m + Data.Function Data.List    
Prelude> let xs = [(1,[2]), (1,[3]), (1,[4]), (2,[1]), (2,[2]), (3,[1])]
Prelude> map (\lst -> (fst $ head lst, concat $ map snd lst)) (groupBy ((==) `on` fst) xs)
[(1,[2,3,4]),(2,[1,2]),(3,[1])]

答案 2 :(得分:0)

请注意,如果相同值的键不连续,groupBy将不会分组。例如:

\> groupBy (==) [1, 2, 1]
[[1],[2],[1]]

因此,您需要确保传入已排序的列表。 另一种方法是使用Data.Map和右折:

import Data.Map (empty, alter, toList)

fun :: (Foldable t, Ord k) => t (k, [a]) -> [(k, [a])]
fun = toList . foldr go empty
    where
    go (k, x) acc  = alter (inc x) k acc
    inc x Nothing  = Just x
    inc x (Just y) = Just (x ++ y)
无论列表是否排序,

都可以正常工作:

\> fun [(1,[2]), (1,[3]), (1,[4]), (2,[1]), (2,[2]), (3,[1])]
[(1,[2,3,4]),(2,[1,2]),(3,[1])]

\> fun [(3,[1]), (1,[2]), (2,[1]), (1,[3]), (2,[2]), (1,[4])]
[(1,[2,3,4]),(2,[1,2]),(3,[1])]