我想过滤不满足属性的列表的最后一个元素。一个例子是
smallerOne :: a->Bool
smallerOne x = x < 1
函数filterLast应该给出
filterLast smallerOne [1, -2, -3, -4, 5]
[1, -2, -3, -4] //Filters the last element that is not smaller than 1
这是我的代码(我是初学者,对于不好的尝试感到抱歉)
filterLast :: (a -> Bool) -> [a] -> [a]
filterLast p [] = []
filterLast p xs
| p (last xs) = filterLast p (init xs) : last xs
| otherwise = init xs
感谢您的帮助
答案 0 :(得分:6)
导致filterLast
编译的最小变化是使用(++)
而不是(:)
,如:
filterLast p xs
| p (last xs) = filterLast p (init xs) ++ [last xs]
(其他行保持不变。)(:)
函数专门用于在列表的开头添加一个额外元素,这不是您想要在此处执行的操作。对于smallerOne
,您可以按照错误消息建议的方式更改类型签名,因此:
smallerOne :: (Num a, Ord a) => a->Bool
答案 1 :(得分:4)
以下是if (array[i] > biggestInt)
的一种可能实现方式:
filterLast
我们的想法是重复使用filterLast :: (a -> Bool) -> [a] -> [a]
filterLast p = go []
where go chunk xs = case span p xs of
(left, []) -> left
(left, (r:right)) -> chunk ++ left ++ go [r] right
将序列分成两部分:左半部分都满足谓词,然后右半部分从第一个不满足谓词的元素开始。如果没有右半边,那么我们可以直接返回左半边。否则,我们必须:
对于大型列表(尤其是无限列表!)而言,这比使用span
和last
的问题时使用的方法更有效。但如果这对你来说不是一个重要的问题,那么简单地应用Daniel Wagner的回答中提出的修正将会为你提供一个你会发现更容易理解的功能。
编辑:正如评论中所建议的那样,您可以通过将此函数重命名为init
然后定义一个角来修复一个角落案例(所有项目都满足谓词的无限列表)委托给它的新filterLast'
:
filterLast
请注意,仍有一些序列在不产生输出的情况下发生分歧,例如filterLast :: (a -> Bool) -> [a] -> [a]
filterLast p xs = left ++ filterLast' p right
where (left, right) = span p xs
。但我认为任何实现都无法解决这个问题,因为你永远不知道是否在输出列表中包含filterLast (< 1) $ 10 : repeat -1
,因为你永远不会找到大于1的另一个元素。
答案 2 :(得分:-1)
你想要做的是颠倒列表并在他们不满足财产时采取元素。元素满足属性的那一刻,你放弃它并占据列表的其余部分。这很自然地转换为haskell代码。
filterLast :: (a -> Bool) -> [a] -> [a]
filterLast p = reverse . uncurry (++) . dropHeadSnd . span p . reverse
where
dropHeadSnd (x, y) = (x, tail' y)
tail' [] = []
tail' (x:xs) = xs
(++)降低了代码的效率,虽然它不是渐近效率,但消除(++)会提高你的性能。
filterLast :: (a -> Bool) -> [a] -> [a]
filterLast p = reverse . helper . reverse
where
helper [] = []
helper (x:xs) | p x = xs
| otherwise = x:helper xs
上述两个函数都在列表上使用两次迭代。但是请记住递归,你可以从后面和前面获取信息。我们使用递归调用来确定是否存在满足'p'的任何后续元素。
f :: (a -> Bool) -> [a] -> [a]
f p = snd . helper
where
helper [] = (False, [])
helper (a:as) | p a && flag = (flag, a:as')
| p a = (True, as')
| otherwise = (flag, a:as')
where
(flag, as') = helper as
答案 3 :(得分:-4)
smallerOne :: (Ord a, Num a) => a -> Bool
smallerOne x = x < 1
filterLast :: (a -> Bool) -> [a] -> [a]
filterLast p (x:[]) = if (p x) then x:[] else []
filterLast p (x:xs) = x : filterLast p xs
这是您问题的解决方案。现在,还有一些解释:
smallerOne ::(Ord a,Num a)=&gt; a - &gt;布尔
您必须包含类约束Ord
和Num
,因为您正试图通过此<
比较运算符来设置数字。您可以在此处阅读更多内容:http://learnyouahaskell.com/types-and-typeclasses#typeclasses-101
filterLast
是通过pattern matching
实现的,Haskell非常聪明,将进入与给定列表匹配的分支,因此他将进入此分支:
filterLast p(x:[])= if(p x)then x:[] else []
仅当剩下一个元素时,即last element
。
你说你是初学者,我真的推荐你这个教程,http://learnyouahaskell.com/chapters,这很酷。