【问题标题】:Haskell and manipulating a list of tuplesHaskell 和操作元组列表
【发布时间】:2023-03-18 01:42:02
【问题描述】:

好吧,我遇到了一个问题,基本上我被告知要制作一个多重集或一个元组列表。 (Char,Int) 然后我必须编写一个函数来获取一个项目并将其插入到这个列表中,但是如果列表中已经有一个匹配的元组,它会增加 Int。 即我有一个列表 [(p,2),(w,3)] 并且我得到另一个 w 它应该给出 [(p,2),(w,4)] 你会怎么做,我试过了

listAdd :: Char->Int->ListOfT -> ListOfT
listAdd c i l
    |length l == 0 =(c,i):l
    |fst l == c = (c,i+1):l

但这会产生大量错误,我需要在该点删除列表元素并将其替换为 (c,i+1),那么如何从列表中删除以及如何获得 i+1?另外,您如何创建一个遍历列表中所有元素的循环? 而且我不能使用任何导入数据的东西 我知道这要求很多,但任何帮助都会非常感谢。 新

好的,可以修改这段代码,这样它就可以用来制作任何项目的元组,而不仅仅是字符。所以我可以加载它并用搅拌器制作一个元组列表,关闭它然后再次加载它并制作一个整数元组列表?

【问题讨论】:

  • "我有一个列表 [(p,2),(w,3)],我得到另一个 w 它应该给出 [(p,2),(w,4)]" 所以你的函数应该有签名Char -> ListOfT -> ListOfT,对吧?

标签: list haskell functional-programming


【解决方案1】:

好的,我认为你的想法不错,你只需要弄清楚细节。

您询问的 循环 通常要么使用递归(因为列表是一个好主意的递归结构),要么使用一些高阶函数,如 mapfilter、@ 987654323@, ...这将对你隐藏递归(你可以说他们抽象出重复的东西) - 在这种情况下,我认为最简单的方法就是使用你开始的方法并使用直接递归。

这是一个简单的版本(你可能想要扩展),它做基本的事情:

listAdd :: Char -> [(Char,Int)] -> [(Char,Int)]
listAdd c [] = [(c,1)]
listAdd c ((c',i):xs)
  | c' == c = (c,i+1):xs
  | otherwise = (c',i) : listAdd c xs

如您所见,第一种情况与您的情况非常相似:如果字典(第二个参数)是空列表,那么您只需添加一个带有要插入的字符和数字 1 的新元组

如果不是,则检查字典中的第一个元素是否具有相同的字符(此处为c'),如果是,则增加计数,如果不是,则让该元素保持原样并递归搜索其余元素字典。

另外请注意,您可以在这里使用模式匹配,不仅可以将字典解构为 head::tail 形式,还可以将头部解构为 (..,..) 元组部分。

如果您愿意,可以在其中使用 @ 并让第二种情况更简洁:

listAdd :: Char -> [(Char,Int)] -> [(Char,Int)]
listAdd c [] = [(c,1)]
listAdd c (x@(c',i):xs)
  | c' == c   = (c,i+1):xs
  | otherwise = x : listAdd c xs

PS:如果你想知道为什么我没有使用你的Int 参数?因为如果已经有一个值,我不知道你想用它做什么 - 这是一个我只是将它添加到它的版本(似乎合理):

listAdd :: Char -> Int -> [(Char,Int)] -> [(Char,Int)]
listAdd c i [] = [(c,i)]
listAdd c i (x@(c',i'):xs)
  | c' == c = (c,i+i'):xs
  | otherwise = x : listAdd c i xs

【讨论】:

    【解决方案2】:

    仅使用递归函数的列表操作对于初学者来说确实很难理解,但在这种情况下,它们应该很好地解决问题。

    让我们从更好的签名和助手开始。

    type MyList = [(Char, Int)]
    
    listAdd :: Char -> MyList -> MyList
    listAdd p l = listAdd' p [] l
    

    请注意,我已将签名更改为仅接受 Char;我们不需要提供初始计数,因为如果列表中当前没有此类元素,我们将在添加新元素时将其设置为 1。

    好的,这就是基本骨架。帮助器只是为了更容易存储列表的“已处理”部分。我们来看看:

    listAdd' :: Char -> MyList -> MyList -> MyList
    

    首先,我们添加递归结束条件:

    listAdd' p left [] = left ++ [(p, 1)]
    

    这意味着如果我们之前没有找到要替换的元素,我们可以在最后添加它。

    listAdd' p left (x:right) = if p == fst x
        then left ++ [(fst x, snd x + 1)] ++ right
        else listAdd' p (left ++ [x]) right
    

    好的,现在我们将“正确”部分拆分为它的第一个元素和其余部分。来看看if

    • 如果我们设法找到了元素,我们可以通过将列表的其余部分附加到修改后的元素和我们之前的元素来结束计算
    • 如果仍然不是,我们继续递归。

    作为最后的补充说明,您可以轻松地将 Char 更改为 Eq a => a 以允许您的函数适用于任何可以直接比较的类型,包括 Char

    【讨论】:

      猜你喜欢
      • 2021-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-24
      • 2017-04-05
      相关资源
      最近更新 更多