首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用zipWith计算列表元素的差异

使用zipWith计算列表元素的差异
EN

Stack Overflow用户
提问于 2019-04-20 22:55:01
回答 3查看 674关注 0票数 2

我必须创建一个名为difference的函数,在这个函数中,我用zipWith计算每一对的差异,并将其放入一个列表中。

例如,differences [1..5] == [1, 1, 1, 1]

所以[2-1, 3-2, 4-3, 5-4] == [1, 1, 1, 1]

我想列一张元组的清单,如下所示:

代码语言:javascript
复制
[1..5] = [(1,2), (2,3), (3,4), (4,5)]

然后像这样使用列表组合:

代码语言:javascript
复制
[zipWith (-) a b | a <- y, b <- x]

其中x是元组的第一个元素,y是第二个元素。

函数类型为differences :: Num a => [a] -> [a]

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-04-20 23:04:38

您就快到了--但是zipWith本身返回一个列表,所以您不希望将其放入列表理解中,除非您希望结果是列表列表(这里不需要)。

zipWith (-)在这里绝对是正确的主意-它需要2个列表,并给出一个新的列表,通过取给定列表的对应元素之间的差异。在这种情况下,您的输出列表比一个输入列表要短一个元素,您希望在两个列表上使用zipWith (-),这些列表包括:

  • 给定列表的所有元素,除第一个元素外
  • 给定列表中的所有元素,最后一个除外。

Haskell已经为我们提供了方便的函数,即尾部初始化

所以你要找的函数是:

代码语言:javascript
复制
differences xs = zipWith (-) (tail xs) (init xs)

请注意,这并不理想,因为如果inittail都是空的,那么xsxs都会导致运行时出错。如果您将空列表呈现给此函数(尽管您可能会认为没有空列表,因为您将从一个单例列表中获得一个空列表),则输出空列表是有意义的,因此您可以通过模式匹配来定义函数以显式地迎合空列表,从而避免运行时崩溃:

代码语言:javascript
复制
differences [] = []
differences xs = zipWith (-) (tail xs) (init xs)

虽然我个人认为这很好,而且非常明确,但实际上并不需要同时使用inittail --如果给出长度不等的列表,zipWith工作得很好,因为它只会将较大的列表缩小到大小。因此,differences xs = zipWith (-) (tail xs) xs是一个可行的、稍微简单一些的替代方案。

票数 3
EN

Stack Overflow用户

发布于 2019-04-20 23:43:09

罗宾·齐格蒙德的回答的基础上,函数的Applicative实例在这里工作得很好:

代码语言:javascript
复制
(f <*> g) xs == f xs (g xs)

所以

代码语言:javascript
复制
differences = zipWith subtract <*> tail

(其中subtract = flip (-).)

票数 3
EN

Stack Overflow用户

发布于 2019-04-22 02:20:02

正如4卡斯尔所暗示的,在-less解中使用drop 1而不是tail,意味着我们可以省略[]的情况,如drop 1 [] = [] (与tail []不同,tail []会导致运行时错误):

代码语言:javascript
复制
differences xs = zipWith (-) (drop 1 xs) xs

为了与这个没有显式模式解构的解决方案形成对比,我将提到使用inittaildrop的任何拼写。

代码语言:javascript
复制
differences xs@(_:ys) = zipWith (-) ys xs
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55778450

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档