简体   繁体   English

如何检查列表中的下一个元素是否大于 Haskell 中的前一个元素?

[英]How to check if next element in a list is greater than the previous in Haskell?

(I am currently doing an online course on Haskell and this is an exercise. I am not looking for answers, but simply for some pointers on how to proceed!) (我目前正在 Haskell 上做一个在线课程,这是一个练习。我不是在寻找答案,而只是寻求一些关于如何进行的指导!)

I have trouble wrapping my head around this.我很难解决这个问题。 In imperative languages I would simply use a loop, but since Haskell doesn't really have those I am left scratching my head.在命令式语言中,我会简单地使用一个循环,但由于 Haskell 并没有真正让我摸不着头脑。

I need to write a function nextIsGreater:: [Int] -> [Int] that, given a list of numbers, produces a list with all elements of the input list such that the element is followed by a greater number in the input list (the next number is greater).我需要编写一个 function nextIsGreater:: [Int] -> [Int] ,给定一个数字列表,生成一个包含输入列表所有元素的列表,使得该元素后跟输入列表中的更大数字(下一个数字更大)。

Here is what I've managed to come up with so far.到目前为止,这是我设法想出的。

nextIsGreater :: [Int] -> [Int]

nextIsGreater xs = [x | x <- init xs, y <- tail xs, x < y]

So far it works if I have only two numbers in the list.到目前为止,如果我在列表中只有两个数字,它就可以工作。 Say [0,5], it returns [0] as it is supposed to.说 [0,5],它按预期返回 [0]。 If I have, say [0,5,6] then my code seems to check the 0 against both of the next numbers in the list and returns [0,0,5], when it should return [0,5].如果我有,比如 [0,5,6],那么我的代码似乎会根据列表中的两个下一个数字检查 0 并在它应该返回 [0,5] 时返回 [0,0,5]。 How could I compare each adjacent number to eachother?我怎样才能将每个相邻的数字相互比较?

Not a bad attempt, but不错的尝试,但是

   [x | x <- init xs, y <- tail xs, x < y]

corresponds to a nested loop: you choose x from init xs , and then for each of these choices you pick all possible y from tail xs .对应于一个嵌套循环:您从init xs中选择x ,然后对于这些选择中的每一个,您tail xs中选择所有可能的y

To make the idea work as intended, you'd need to use {-# LANGUAGE ParallelListComp #-} or equivalently zip the sources:为了使这个想法按预期工作,您需要使用{-# LANGUAGE ParallelListComp #-}或等效的zip来源:

nextIsGreater xs = [x | (x,y) <- zip (init xs) (tail xs), x<y]

But there's a simpler way to obtain all choices of two consecutive elements, with tails :但是有一个更简单的方法来获得两个连续元素的所有选择, tails

nextIsGreater xs = [x | (x:y:_) <- tails xs, x<y]

The intention of this exercise is almost certainly to have you write a standard recursive solution using pattern matching, not use list comprehensions or higher level functions or anything like that.这个练习的目的几乎肯定是让你使用模式匹配编写一个标准的递归解决方案,而不是使用列表理解或更高级别的函数或类似的东西。

If the course is any good, you should already have covered some recursive list-to-list transformations, functions with definitions of the form:如果课程不错,您应该已经涵盖了一些递归的列表到列表转换,以及具有以下形式定义的函数:

foo :: [Int] -> [Int]
foo (x:xs) = ... something involving "x" and "foo xs" ...
foo [] = ...

or similar, and you're expected to write something along the same lines.或类似的,你应该按照同样的思路写一些东西。

Here's a first hint, with further spoilers below.这是第一个提示,下面还有更多剧透。

A simple way of writing a recursive function that operates on adjacent elements of lists is to write a pattern that names the first two elements:编写对列表的相邻元素进行操作的递归 function 的一种简单方法是编写一个命名前两个元素的模式:

foo (x:y:zs) = ...

The "..." can operate on x and y , and then perform a recursive call to process the "rest" of the list. “...”可以对xy进行操作,然后执行递归调用以处理列表的“其余部分”。 The recursive call might be either foo zs or foo (y:zs) (or switch between those based on some condition), depending on what the function is doing.递归调用可能是foo zsfoo (y:zs) (或根据某些条件在它们之间切换),具体取决于 function 在做什么。

Because this pattern will only match lists with at least two elements, you will usually also need patterns to match both one-element and empty lists:因为这个模式只会匹配至少有两个元素的列表,你通常还需要模式来匹配一个元素和空列表:

foo [x] = ...
foo [] = ...

If that's not clear enough, let me refresh your memory on basic recursive list-to-list transformations starting with an example that doesn't inspect adjacent elements.如果这还不够清楚,让我从一个检查相邻元素的示例开始,刷新您的 memory 基本递归列表到列表转换。

SPOILERS剧透

. .

. .

. .

Suppose we want to filter out all even elements from a list.假设我们要从列表中过滤掉所有偶数元素。 A recursive solution would consider the two cases:递归解决方案将考虑两种情况:

evens (x:xs) = ...
evens [] = ...

For the first case, the extraction of all evens from x:xs either includes x plus all the evens from xs (ie, evens xs ) or excludes x and includes only evens xs , depending on whether or not x itself even:对于第一种情况,从x:xs中提取所有偶数要么包括x加上xs中的所有偶数(即evens xs,要么排除x并仅包括偶数evens xs ,具体取决于x本身是否偶数:

evens (x:xs) | even x = ...
             | otherwise = ...

In particular, if x is even, the answer should include x together with evens xs :特别是,如果x是偶数,答案应该包括xevens xs

evens (x:xs) | even x = x : evens xs

and if x is odd, the answer just should include evens xs :如果x是奇数,答案就应该包括偶数evens xs

             | otherwise = evens xs

The final case is the subset of even numbers from the empty list, which is just the empty list:最后一种情况是空列表中偶数的子集,它只是空列表:

evens [] = []

giving the complete definition:给出完整的定义:

evens :: [Int] -> [Int]
evens (x:xs) | even x = x : evens xs
             | otherwise = evens xs
evens [] = []

The main difference in your example is that the decision to include x depends not only on x but on the element appearing after x , so let's consider a slightly different problem: take a list and output all elements that are followed by an even number.您的示例中的主要区别在于包含x的决定不仅取决于x还取决于出现在x之后的元素,因此让我们考虑一个稍微不同的问题:获取一个列表和 output后跟偶数的所有元素。

We might consider starting with a similar structure:我们可能会考虑从类似的结构开始:

beforeEvens (x:xs) | ... = x : beforeEvens xs     -- include x
                   | otherwise = beforeEvens xs   -- exclude x
beforeEvens [] = []

where "..." checks to see if the element after x (ie, the first element of xs ) is even.其中“...”检查x之后的元素(即xs的第一个元素)是否为偶数。 For example, we might call a separate function to check this:例如,我们可能会调用一个单独的 function 来检查:

beforeEvens (x:xs) | headIsEven xs = x : beforeEvens xs
                   | otherwise     = beforeEvens xs
beforeEvens [] = []

You ought to be able to write a decent definition of headIsEven to complete this.您应该能够编写headIsEven的体面定义来完成此操作。 Bonus points if instead of using head , it uses pattern matching.如果不使用head而是使用模式匹配,则可以加分。 Note the special case headIsEven [] should return False .注意特殊情况headIsEven []应该返回False

A more direct approach, though, is to take advantage of the fact that patterns can be used to examine multiple elements at the start of the list.不过,更直接的方法是利用模式可用于检查列表开头的多个元素这一事实。 Here, we match a pattern that names the first two elements x and y , plus the rest of the list zs :在这里,我们匹配一个命名前两个元素xy的模式,加上列表zs的 rest:

beforeEvens (x:y:zs) | even y = x : beforeEvens (y:zs)
                     | otherwise = beforeEvens (y:zs)
beforeEvens [x] = []
beforeEvens [] = []

Note a couple of tricky points here.请注意这里的几个棘手点。 If we match against the pattern (x:y:zs) , then we have to be careful about whether we recurse on y:zs or zs alone.如果我们匹配模式(x:y:zs) ,那么我们必须小心我们是否单独递归y:zszs It depends on whether y should or shouldn't be considered for inclusion in the output. Also, the pattern (x:y:zs) won't match a singleton list, so we need an extra pattern match on that.这取决于y是否应该被考虑包含在 output 中。此外,模式(x:y:zs)不会匹配 singleton 列表,因此我们需要一个额外的模式匹配。

Because the last two cases are the same, we can combine them into a single case:因为最后两个案例是一样的,我们可以将它们合并为一个案例:

beforeEvens (x:y:zs) | even y = x : beforeEvens (y:zs)
                     | otherwise = beforeEvens (y:zs)
beforeEvens _ = []

You should find it relatively straightforward to modify beforeEvens to write your nextIsGreater function.您应该会发现修改beforeEvens以编写nextIsGreater function 相对简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Haskell-检查列表中的所有项目是否都大于1 - Haskell - Check if all items in list are greater than 1 如何检查列表中的数字是否大于并延续到列表中的下一个数字 - How to check if number in a list is greater than and in continuation to next number in list 如何检查Prolog列表中的每个元素是否大于0? - How to check if each element in Prolog list is greater than 0? 计算一个元素大于其在列表中的前一个元素的次数 - Count the number of times an element is greater than its previous element in a list 如何检查haskell列表中是否存在元素? - How to check if an element exists in list in haskell? 如何检查列表中大于或小于var整数 - How to check a list for greater or less than var integers 在 Pandas 中:如何检查列表元素是否大于数据框列值 - In Pandas : How to check a list elements is Greater than a Dataframe Columns Values 如何检查以前的元素是否与python中的next elemnt类似 - how to check if previous element is similar to next elemnt in python Python - 如何检查列表中的下一个值是否与上一个相同? - Python - How to check if the next value in a list is the same as the previous? Haskell - 删除元组列表中大于 n 的元素 - Haskell - Remove elements in a list of tuples that are greater than n
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM