【问题标题】:Comparing a List of tuples in haskell比较haskell中的元组列表
【发布时间】:2015-10-20 13:02:46
【问题描述】:

好的,我对 Haskell 非常陌生,因为我今天早上开始学习,我的任务是获取 2 个元组列表 [("s",1)..],如果它们都相同,则返回 true否则元素返回 false。 到目前为止,我正在考虑从列表 1 中获取第一个元素并将其与列表 2 中的所有元素进行比较,然后对所有元素执行此操作,然后返回 true 或 false。我不知道如何跟踪所有布尔值,如果有错误就很容易

|head list1 =/ elementList2 = False

但我只是让自己感到困惑,到目前为止,我已经定义了 List

listCheck :: List->List -> Bool
listCheck (h1:t1) (h1:t1)
    | h1 == [] = True
    | fst (head h1) /= fst (head h2) = False
    | snd (head h1) /= snd (head h2) = False
    | otherwise = listCheck (t1) (t2)

有什么建议吗? 列表可以按任何顺序排列,因此 [("a",1),("b",1)] 和 [("b",1),("a",1)] 是相等的。列表的顺序无法更改。

【问题讨论】:

  • 我的想法是你通过列表​​检查
  • 你能解释一下'如果他们比较相同的元素则返回真否则返回假'的意思吗?你的意思是如果它们包含完全相同的元素,它应该返回true,而不管顺序如何?还是相同顺序的相同元素?或者如果列表之间至少有一个共同元素?请准确。
  • 听起来你想要listCheck = (==)listCheck = Data.List.isPrefixOf

标签: list haskell functional-programming tuples


【解决方案1】:

我认为获取列表的头部并使用它创建一个相等函数是合理的。使用List library中的anyall与尾部进行比较。

因为这是一个大学练习,我猜你不想给你答案;-)

【讨论】:

    【解决方案2】:
    listCheck l1 l2 = sort l1 == sort l2
    

    如果列表元素是完全有序的,它们会正常工作,通常情况下是字符串、数字等(以及这些元素的自然元组)。

    如果您的元素没有排序,事情会变得更加困难,但我认为您不会经常遇到这种情况。

    【讨论】:

      【解决方案3】:

      我总是建议新手处理这个问题的方式是这样的:

      1. 寻找使用标准库函数解决问题的方法。
      2. 当您成功后,为您使用的每个库函数编写您自己的版本。

      在这种情况下,您对自己的想法的描述可以巧妙地融入#1 风格的解决方案中。让我们引用它:

      到目前为止,我正在考虑从列表 1 中获取第一个元素并将其与列表 2 中的所有元素进行比较,然后对所有元素执行此操作,然后返回 true 或 false。

      在这里,不要考虑只对第一个元素执行此操作,而是将图片对所有元素执行相同的操作,作为解决方案的一个步骤。有一个标准函数可以捕捉到这种模式:

      -- The `map` function applies the function given as the first argument
      -- to all of the elements of the second argument.  The result is a list
      -- of all the individual results.
      --
      -- Example:
      --
      -- >>> map (+10) [1, 2, 3, 4]
      -- [11, 12, 13, 14]
      map :: (a -> b) -> [a] -> [b]
      

      因此,如果您可以编写一个函数来测试 one 值是否存在于第二个列表中,则可以使用 map 将该函数应用于 all 元素第一个列表:

      step1 :: Eq a => [a] -> [a] -> [Bool]
      step1 xs ys = map checkOne xs
        where checkOne x = _fillInTheBlank
      

      _fillInTheBlank 位被称为“洞”——你应该在其中实际编写正确的代码!)

      第二步是检查[Bool] 以查看是否所有元素都是True。如果它们是,则返回True,如果至少有一个是错误的,则返回False。也有一个标准函数:

      -- Returns `False` if any element of the list is `False`, `True` otherwise.
      and :: [Bool] -> Bool
      

      现在:

      listCheck :: Eq a => [a] -> [a] -> Bool
      listCheck xs ys = and (map checkOne xs)
        where checkOne x = _fillInTheBlank
      
      map :: (a -> b) -> [a] -> [b]
      -- Write your own version of `map`
      
      
      and :: [Bool] -> Bool
      -- Write your own version of `and`
      

      请注意我所做的:我已将问题拆分为更小的部分,每个部分我都可以使用 mapand 之类的函数来解决,这在许多其他情况下都很有用。这就是你应该为之奋斗的目标。

      【讨论】:

      • 您的意思可能是and,而不是all?虽然all pred 当然比and . map pred 更受青睐。
      • 你上次sn-p中listCheck有括号错误吗?
      • @Bergi:哎呀,是的,我的意思是and。不过,我没有看到任何括号错误。
      • 啊,是的,那是一回事。我原以为all (… checkOne) xs 之类的东西(右括号移位),但在这种情况下,map 放错了位置。
      【解决方案4】:

      如果您的目标是比较每个列表的第 n 个元素,那么您已经非常接近了。唯一的问题是您正在进行模式匹配以将两个列表分开为头/尾,然后就像您没有这样做一样,再次调用 headtail

      listCheck :: (Eq a, Eq b) => [(a,b)] -> [(a,b)] -> Bool
      listCheck xs ys
          | xs == [] = True
          | fst (head xs) /= fst (head ys) = False
          | snd (head xs) /= snd (head ys) = False
          | otherwise = listCheck (tail xs) (tail ys)
      

      这远不是最优雅的做事方式,但它是我能找到的最接近你似乎试图写的东西。

      【讨论】:

      • 在可以进行模式匹配时不要使用headtail。应避免使用偏函数,尤其是初学者。
      • ...尤其是如果这会诱使您将它们用于可能为空的列表中。
      • 正如我所说,这不是做事的最佳方式,但似乎最接近问题中提出的方法。如果我只是从头开始重新实现这个功能,那将是完全不同的:如果不需要短路行为,则类似于listCheck = (and .) . zipWith (==)listCheck = (==)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-28
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      • 2016-04-01
      相关资源
      最近更新 更多