【问题标题】:Combining the second element of a tuple into a list based on the first element [duplicate]根据第一个元素将元组的第二个元素组合成一个列表[重复]
【发布时间】:2017-12-14 13:23:05
【问题描述】:

我一直在努力尝试根据我的元组中的第一个元素来获得一个字符串列表。

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有关。我认为需要附加一个函数。

【问题讨论】:

  • 使用Data.MultiMap 你可以做到assocs . fromList
  • 即使只有Data.Map,您也可以使用assocs . (unionsWith (++)) . map (\(x,y) -> M.singleton x [y])
  • assocs . fromListWith (++) . (map . fmap) (:[])

标签: haskell


【解决方案1】:

我不明白你想在你的代码中做什么,所以我必须自己建立起来。我是这样处理它的:我们将把我们的起始列表放在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 . fstsnd 函数。但我还没有想到。

相反,受@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])]

【讨论】:

    【解决方案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"])]
    

    【讨论】:

      【解决方案3】:

      您也可以使用Data.Map.Strict 中的fromListWith 来执行此操作:

      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"])]
      

      【讨论】:

        猜你喜欢
        • 2022-12-07
        • 2013-09-25
        • 2022-11-16
        • 1970-01-01
        • 2021-03-11
        • 1970-01-01
        • 2022-10-21
        • 2022-11-27
        • 2020-10-08
        相关资源
        最近更新 更多