我一直在尝试根据元组中的第一个元素来获取字符串列表。
Ex:
[('a', "Hello"),('b', "Goodbye"), ('a', "World"), ('b', "World")]
->
[('a', ["Hello","World"]),('b',["Goodbye","World"])]
我认为我已经非常接近,但我没有得到正确的输出。
map (foo . unzip) . groupBy (\st en -> fst st == fst en) . sort
where edge (name, futureList) = (head name, futureList)
我猜它最终与futureList有关。我认为需要附加一个功能。
答案 0 :(得分:4)
我不明白你在代码中想要做什么,所以我必须自己构建它。以下是我接触它的方法:我们将我们的起始列表放在x
中以简化测试:
> x = [('a', "Hello"),('b', "Goodbye"), ('a', "World"), ('b', "World")]
然后导入groupBy
函数:
Prelude> import Data.List
Prelude Data.List> :t groupBy
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
因此我们可以从元组的第一个元素开始分组:
> groupBy (\x y -> fst x == fst y) x
[[('a',"Hello")],[('b',"Goodbye")],[('a',"World")],[('b',"World")]]
啊,但这不起作用,因为匹配元素彼此不相邻,所以我们需要一个sort
:
> groupBy (\x y -> fst x == fst y) $ sort x
[[('a',"Hello"),('a',"World")],[('b',"Goodbye"),('b',"World")]]
还有一个很棒的功能可以让我们更简洁,on
:
Prelude Data.List> import Data.Function
Prelude Data.List Data.Function> :t on
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
让我们这样做:
> groupBy ((==) `on` fst) $ sort x
[[('a',"Hello"),('a',"World")],[('b',"Goodbye"),('b',"World")]]
我们想要的列表只是这些元组的后半部分:
> map (snd) $ map unzip $ groupBy ((==) `on` fst) $ sort x
[["Hello","World"],["Goodbye","World"]]
字母是前半部分 - 它们都是分组的,所以我们可以只取head
个字母:
> map (head . fst) $ map unzip $ groupBy ((==) `on` fst) $ sort x
"ab"
(将结果读作['a', 'b']
- 字符串只是一个字符列表。)现在我们非常接近,似乎应该有一种方法来组成(,)
函数(元组构造)与我们的两个head . fst
和snd
函数。但我还没想出来。
相反,受到@karakfa's answer的启发,我使用了一个帮手:
> mapFst f (a, b) = (f a, b)
> :t mapFst
mapFst :: (t2 -> t1) -> (t2, t) -> (t1, t)
到达:
> map (mapFst head) $ map unzip $ groupBy ((==) `on` fst) $ sort x
[('a',["Hello","World"]),('b',["Goodbye","World"])]
为.
换出$
会产生一个实际函数,而不显式引用我们的x
测试值:
> (map (mapFst head) . map unzip . groupBy ((==) `on` fst) . sort) x
[('a',["Hello","World"]),('b',["Goodbye","World"])]
最后,两个map
组合在一起可以折叠:
> (map (mapFst head . unzip) . groupBy ((==) `on` fst) . sort) x
[('a',["Hello","World"]),('b',["Goodbye","World"])]
它的类型正如我们所期望的那样:
> :t (map (mapFst head . unzip) . groupBy ((==) `on` fst) . sort)
(map (mapFst head . unzip) . groupBy ((==) `on` fst) . sort)
:: (Ord b, Ord t1) => [(t1, b)] -> [(t1, [b])]
答案 1 :(得分:2)
你有名字混淆(foo vs edge)
基本上是相同的代码
import Data.List(sort,groupBy)
import Data.Function(on)
map (mapFst head . unzip) . groupBy ((==) `on` fst) . sort
where mapFst f (a, b) = (f a, b)
给出
[('a',["Hello","World"]),('b',["Goodbye","World"])]
答案 2 :(得分:0)
您也可以使用fromListWith
中的Data.Map.Strict
来执行此操作:
import Data.Map.Strict (fromListWith, toList)
import Data.List (sort)
groupTuples :: [(Char, String)] -> [(Char, [String])]
groupTuples tuples = [(k, sort v) | (k, v) <- grouped]
where grouped = toList $ fromListWith (++) [(k, [v]) | (k, v) <- tuples]
其工作原理如下:
*Main> groupTuples [('a', "Hello"),('b', "Goodbye"), ('a', "World"), ('b', "World")]
[('a',["Hello","World"]),('b',["Goodbye","World"])]