【问题标题】:Haskell: How do I write a function to combine my list of lists of tuples into a list of tuples? [duplicate]Haskell:如何编写一个函数来将我的元组列表组合成一个元组列表? [复制]
【发布时间】:2018-09-20 21:06:28
【问题描述】:

我正在学习 Haskell,但不确定如何编写函数来访问我的列表。

我要修改的数据是:

[[("String",1, "String", "ABC", 2.0)],[("String",1, "String", "DEF", 2.0),("String",4, "String", "DEF", 2.0)]]

目前,数据是根据最后一个字符串(“ABC”或“DEF”)组合在一起的。我想结合这些信息得到以下输出:

[("String",1, "String", "ABC", 2.0),("String",5, "String", "DEF", 4.0)]

字符串不会改变,但 int/float 会加在一起。

我目前拥有的代码是:

combine :: [(a)] -> (a)
combine [(a)] = (a)

我只是在测试是否可以访问不同大小的列表,但它不起作用。当我尝试访问另一组列表时,它给了我一个错误。

[("CS",273,"A",1,"Lewis, Buck",1.66),*** Exception: Non-exhaustive patterns in function combineInfo

【问题讨论】:

  • 我在this answer 中描述的技术可以非常简单地适应这种变化。

标签: list haskell tuples


【解决方案1】:

您的函数combine 被定义为获取单个元素的列表并返回该元素;给定一个包含零个或多个项目的列表,它会如您所观察到的那样引发运行时错误。编译器会在启用警告的情况下警告此类“非详尽模式”,例如-Wall

如果您有一个值容器,并且您想以某种方式将它们全部组合起来,那么这很好地表明您可以使用折叠。只看这个子列表:

sublist = [("String",1, "String", "DEF", 2.0),("String",4, "String", "DEF", 2.0)]

您可以将这些值与foldr1(或foldl1)组合:

foldr1 :: Foldable t => (a -> a -> a) -> t a -> a

t = [](a -> a -> a) -> [a] -> a

combineGroup xs = foldr1 combine xs
  where
    combine
      (_, x, _, _, y)                 -- Current item in list
      (s1, totalX, s2, name, totalY)  -- Accumulator for results
      = (s1, totalX + x, s2, name, totalY + y)

这假设组永远不会为空;如果可以为空,请使用foldr(或foldl')为累加器提供初始“默认”值:

foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

然后,要将这个函数应用于外部列表中的每个组,只需使用map

map combineGroup groups

如果您想通过直接递归作为学习练习来做到这一点,请查看标准库中mapfoldr 的定义,并尝试手动将它们内联到单个函数中。

另一个改进代码的好方法是将这些元组替换为数据类型,例如:

data Info = Info
  { infoString1, infoString2 :: String
  , infoX :: Int
  , infoName :: String
  , infoY :: Double
  } deriving (Show)  -- Add other classes like Eq, Ord, &c. as needed.

然后可以使用记录更新更清楚地编写折叠以仅更新您关心的字段,而无需手动探索不相关的字段:

combineGroup xs = foldr1 combine xs
  where
    combine current acc = acc
      { x = infoX acc + infoX current
      , y = infoY acc + infoY current
      }

-- OR

{-# LANGUAGE NamedFieldPuns #-}
combineGroup xs = foldr1 combine xs
  where
    combine Info{ x, y } acc@Info{ x = totalX, y = totalY }
      = acc { x = totalX + x, y = totalY + y }

【讨论】:

    猜你喜欢
    • 2015-10-30
    • 1970-01-01
    • 2022-06-15
    • 2022-08-18
    • 1970-01-01
    • 2021-08-02
    • 1970-01-01
    • 2018-10-05
    • 2013-03-25
    相关资源
    最近更新 更多