【问题标题】:Iterate through list of tuples with strings and ints使用字符串和整数遍历元组列表
【发布时间】:2021-01-06 12:49:37
【问题描述】:

所以我有这个功能

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

所以基本上如果我确实获得了销售“星期一”商店日志

并且 storelog 是 storelog = [("Mon",50),("Fri",20), ("Tue",20),("Fri",10),("Wed",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”,然后传入列表当天的销售额。

【问题讨论】:

    标签: list loops haskell tuples


    【解决方案1】:

    您实际上已经实现了 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 程序中默认可用的一组函数/类型/类,没有任何导入——已经包含一些处理这些事情的函数。特别是,sum 用于添加数字列表,filter 用于将列表缩减为仅满足特定条件的元素,map 用于通过对每个元素应用函数从旧列表中获取新列表元素。 mapfilter 和各种折叠确实是使用列表进行函数式编程的“生计”,因此我建议您熟悉并熟悉它们。

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

    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。编写函数的“最佳”方式,就可读性而言,这是一个非常见仁见智的问题。我只是想向您展示还有其他方法可以编写这些函数,以及您将来可能需要的其他类似方法,当您来的时候可能会更有意义稍后再回来查看它们。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-04
      • 1970-01-01
      • 2016-08-21
      • 2021-04-02
      相关资源
      最近更新 更多