取出Haskell中列表中某个元素的最后一次出现

时间:2015-11-13 02:37:02

标签: list haskell recursion

我在编写带有谓词和整数列表的函数时遇到问题,然后消除了满足列表中谓词的最后一个整数。我能够使用下面的函数取出列表中第一次出现的谓词:

fun :: (Int -> Bool) -> [Int] -> [Int]
fun check (s:ss)
 |check s = ss
 |otherwise = s : fun check ss

我需要帮助的是如何修改此函数以取出最后一次出现的整数,而不是第一次出现。例如,fun (<2) [3,4,1,5,0,-3,9]将返回[3,4,1,5,0,9]

3 个答案:

答案 0 :(得分:4)

(由于某些缩进问题,我无法使用where

removeLast :: (a -> Bool) -> [a] -> [a]
removeLast p xs =
    let
        go c  []    = tail (c [])
        go c (x:xs)
            | p x       = c (go (x:) xs)
            | otherwise = go (c . (x:)) xs
    in case break p xs of
        (ok, [])   -> ok
        (ok, x:xs) -> ok ++ go (x:) xs

go收集谓词在差异列表中不存在的元素,并在找到满足谓词元素的新元素后将此列表预先添加到结果中。 break p xs上的模式匹配确保差异列表始终以满足谓词的元素开头,如果它是最后一个,我们可以删除它。

使用无限列表:

main = do
    print $ removeLast (< 2) [3,4,1,5,0,-3,9]        -- [3,4,1,5,0,9]
    print $ removeLast (== 2) [1,3]                  -- [1,3]
    print $ take 10 $ removeLast (< 2) (cycle [1,3]) -- [1,3,1,3,1,3,1,3,1,3]

这是一个混淆版本:

removeLast :: (a -> Bool) -> [a] -> [a]
removeLast p xs = case break p xs of
    (ok, [])   -> ok
    (ok, x:xs) -> ok ++ foldr step (tail . ($[])) xs (x:) where
        step x r c = if p x then c (r (x:)) else r (c . (x:))

答案 1 :(得分:3)

如果你想玩得开心,试试这个版本。

removeLast :: (a -> Bool) -> [a] -> [a]
removeLast p = fst . foldr go ([], False) where
  go x ~(r, more)
    | p x = (if more then x : r else r, True)
    | otherwise = (x : r, more)

这似乎几乎和它一样懒惰,而且很快就达到了目的。它可以通过一些努力更懒惰地生成列表 spine ,但它最大限度地生成列表元素

经过一番思考,我意识到在这种情况下,懒惰的不同方面之间存在一些紧张关系。考虑

removeLast p (x : xs)

我们可以尝试两种方法来确定是否生成[](:)构造函数。

  1. 我们可以查看xs;如果xs不是[],那么我们就可以生成(:)

  2. 我们可以查看p x。如果p xFalse,那么我们就可以生成(:)

  3. 这是唯一的方法,它们的严格性无法比较。唯一的&#34;最大的懒惰&#34;方法是使用并行性来尝试两种方式,这不是最实用的方法。

答案 2 :(得分:0)

这个怎么样:

fun :: (Num a) => (a -> Bool) -> [a] -> [a]
fun check (s:ss)
    |check s = ss
    |otherwise = s : fun check ss

然后,像这样应用fun函数:

reverse $ fun (\ x -> x `mod` 3 == 0) (reverse [1..10])

HTH