Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 使用字符串和整数遍历元组列表_List_Loops_Haskell_Tuples - Fatal编程技术网

List 使用字符串和整数遍历元组列表

List 使用字符串和整数遍历元组列表,list,loops,haskell,tuples,List,Loops,Haskell,Tuples,所以我有这个函数 getSales :: (Num p, Eq t) => t -> [(t, p)] -> p getSales day [] = 0 getSales day ((x,y):xs) | (day == x) = y + (getSales day xs) | otherwise = getSales day XS 所以基本上如果我得到销售“Mon”storelog storelog是storelog=[(“周一”,50),(“周五”,20),(“周二”,2

所以我有这个函数

getSales :: (Num p, Eq t) => t -> [(t, p)] -> p
getSales day [] = 0
getSales day ((x,y):xs) | (day == x) = y + (getSales day xs) | otherwise = getSales day XS
所以基本上如果我得到销售“Mon”storelog

storelog是storelog=[(“周一”,50),(“周五”,20),(“周二”,20),(“周五”,10),(“周三”,25),(“周五”,30)]

它将返回50。但现在我希望能够遍历这样的元组

sales = [("Amazon",[("Mon",30),("Wed",100),("Sat",200)]), ("Etsy",[("Mon",50),("Tue",20),("Wed",25),("Fri",30)]), ("Ebay",[("Tue",60),("Wed",100),("Thu",30)]), ("Etsy",[("Tue",100),("Thu",50),("Sat",20),("Tue",10)])]
使用给定的公司名称,然后我使用getSales查找所询问日期的销售额

sumSales:: (Num p)=> String -> String -> [(String,[(String,p)])] -> p

这是我对给定的公司名称进行迭代的函数,但我很难理解如何迭代元组以找到“Amazon”例如,然后传入几天的销售列表。

您实际上已经实现了
getSales
函数中所需的大部分逻辑-我在下面重复这些,以供参考,尽管整理了递归案例,将保护放在单独的行上,这更具可读性,在实践中通常是这样写的:

getSales :: (Num p, Eq t) => t -> [(t, p)] -> p
getSales day [] = 0
getSales day ((x,y):xs)
  | (day == x) = y + (getSales day xs)
  | otherwise = getSales day XS
对于
sumSales
函数,只需重复此模式即可。唯一重要的区别是:

  • 该函数接受2个参数,而不是1个参数
  • 元组的第二个元素,由上面的
    y
    表示,现在不仅仅是一个数字,而是元组列表。因此,我们不能简单地将其添加到递归调用的结果中。然而,它是一个元组,由一个日期名称和一个数字组成,这正是您在
    getSales
    中已经处理过的情况。因此,解决方案是利用您已经编写的函数
考虑到上述因素,我们得到:

sumSales:: (Num p) => String -> String -> [(String, [(String, p)])] -> p
sumSales company day [] = 0
sumSales company day ((x, y) : xs)
  | company == x = getSales day y + sumSales company day xs
  | otherwise = sumSales company day xs
我相信你会这么做的

然而,我并不特别喜欢这两个函数。它们非常“嘈杂”,在您理解函数的功能之前,需要处理很多细节——而且,这两个函数的重要部分或多或少是相同的。特别是,在函数式编程中,编写类似于“总结”列表信息的函数的一种常见方法是使用“折叠”。因此,您可以用这种方式重写函数,它使用
foldr
来抽象出这两种方法中的常见递归模式:

getSales day = foldr (\(x, y) sum -> if x == day then y + sum else sum) 0
sumSales company day = foldr (\(x, sales) sum -> if x == company then getSales day sales + sum else sum) 0
在我看来,这是更好的,但仍然不是很好。在每种情况下,我们用于折叠的函数之间仍然存在重复-都只是检查一个条件,并使用它添加一个新术语或不添加新术语

Haskell标准库——事实上,即使是Prelude,每个Haskell程序中默认可用的函数/类型/类集,没有任何导入——已经包含了一些处理这些事情的函数。特别是,可以添加一个数字列表,将列表缩减为满足特定条件的元素,以及通过对每个元素应用函数从旧列表中获取新列表<代码>映射,
过滤器
和各种折叠实际上是列表函数编程的“面包和黄油”,因此我建议您熟悉并熟悉它们

使用这些常用工具,我们可以以更容易理解的形式编写这两个函数:

getSales day = sum . map snd . filter (\(x, _) -> x == day)
sumSales company day = sum . map (getSales day . snd) . filter (\(x, _) -> x == company)
(有人可能会说,我在“零分”方面做得太过分了,尽管我本可以更进一步,把例如
\(x,\)->x==day
写成
(==day)。fst
。“最好”编写函数的方法,就可读性而言,在很大程度上是一个意见问题。我只是想告诉您,还有其他方法可以编写这些函数,以及您将来可能需要的其他类似方法,当您稍后再来查看它们时,这些方法可能会对您更有意义。)