Haskell并操纵元组列表

时间:2015-10-15 12:39:21

标签: list haskell functional-programming

好的,所以一直遇到一个问题,基本上我被告知制作多重集或元组列表。 (Char,Int)然后我必须编写一个函数,它接受一个项并将其插入到这个列表中,但是如果列表中已经有匹配的元组,它会增加Int。 即我有一个清单[(p,2),(w,3)]我得到另一个它应该给[(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

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

好的,这段代码可以摆弄,所以它可以用来制作任何项目的元组而不仅仅是字符。所以我可以加载它并制作一个带有stirngs的元组列表,然后关闭它然后重新加载它并创建一个int元组列表?

2 个答案:

答案 0 :(得分:3)

好吧我觉得你的想法不错,你只需要直接了解细节。

你询问的循环通常是通过递归完成的(因为列表是一个很好的想法的递归结构),或者是一些更高阶函数,如mapfilterfoldr,...这将隐藏你的递归(你可以说它们抽象出重复的东西) - 在这种情况下,我认为最简单的方法就是和你一起去开始并使用直接递归。

这是一个简单的版本(你可能想要扩展),它可以完成基本的工作:

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

答案 1 :(得分: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

好的,现在我们分开了'#34;对"部分到它的第一个元素和其余部分。我们来看看if

  • 如果我们设法找到元素,我们可以通过将列表的其余部分附加到修改后的元素以及之前的内容来结束计算
  • 如果还没有,我们继续递归。

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