【问题标题】:Remove elements at positions n and n-1 in a Haskell list, when n fits a predicate当 n 适合谓词时,删除 Haskell 列表中位置 n 和 n-1 处的元素
【发布时间】:2014-01-17 12:03:17
【问题描述】:

假设我有一个从220 的所有整数的列表。

[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

我还有一个函数f x,它返回TrueFalse。当我将此函数应用于位置n 的元素并且它等于True 时,我想删除它及其前面的元素(即位置n-1 的元素)。我想继续这样做,直到列表中没有函数等于 True 的元素以及它们之前的元素。

示例: 假设位置11 的元素等于13,符合谓词。然后我想删除位置10 的元素,它也等于12。之后我的最终名单将是:

[2,3,4,5,6,7,8,9,10,11,14,15,16,17,18,19,20]

我们还假设位于4815 的元素是唯一符合谓词的元素(除了位于13 的元素)。删除它们及其前面的元素后,我的最终列表将如下所示:

[2,3,4,7,8,11,14,15,18,19,20]

我是一个没有经验的 Haskell 程序员,只是为了好玩。我曾想过使用某种 lambda 函数作为过滤器的谓词,或者创建一个像 listRemove xs ys 这样的函数来删除 xs 的所有元素,这些元素也是 ys 的一个元素,但我对两者都有点迷茫。

任何帮助将不胜感激!

编辑:我要做的是解决Project Euler 问题,即#179。谓词f x 是检查x 是否为质数。因此,我可以肯定地说不存在极端情况——例如。没有像[x, x, t, t] 这样的情况,其中t 是谓词成立的数字,因为除了23 之外,不存在两个连续的素数整数,我可以在我的解决方案。相反,您可以获得的最接近的是[x, t, x, t],在这种情况下,我想删除所有这些元素。

【问题讨论】:

  • 我不确定自从你的previous, similar question 之后发生了什么变化。您似乎有某种目的,但您没有与我们分享-也许您可以解释原始问题,因为可能有一种直接解决该问题的优雅方法。请阅读XY problems
  • 从表面上看,您可以稍微重新整理上一个问题的答案,但是您对上一个问题的编辑介绍了这个问题,其中包含的想法比这更多。您提到替换或编辑值。如果您想用 20*5 替换 19 和 20,因为 20 满足您的谓词,您是否也想根据您的谓词检查新的 100?您是否尝试过旧问题的回答者提供的代码?
  • 您的删除操作没有明确定义,您必须指定一个顺序。那么极端情况(x,x,t,t)呢,其中t 是谓词所在的元素?它应该返回 (),因为 (x,x,t,t) -> (x,t) -> () [我们删除内部 (x,t)] 或 (x,x) [我们删除 (t ,t)]?
  • @Zeta 另一个好点。让我们谈谈问题背景的另一个原因。 (不过,我认为您的意思是方括号。)
  • @chunksOf50:格式不是 Haskell 特定的,只是想显示一个有序集合。

标签: list haskell predicate


【解决方案1】:

已解决 “当 n 适合谓词时,删除 Haskell 列表中位置 n 和 n-1 处的元素”

filter' :: (a -> Bool) -> [a] -> [a]
filter' f xs = map (\i -> xs!!i) $
                 [i | i <- [0 .. s], fit i && (i >= s || fit (i+1))]
               where s = length xs - 1
                     fit i = not (f (xs!!i))

用法

*Main> filter' (==4) [1,2,3,4,5,6]
[1,2,5,6]

*Main> filter' (\n -> n `mod` 7 == 0) [1..23]
[1,2,3,4,5,8,9,10,11,12,15,16,17,18,19,22,23]

*Main> filter' (\n -> n `elem` [4,5,6]) [1..10]
[1,2,7,8,9,10]

O(n)成本可能是

filter' :: (a -> Bool) -> [a] -> ([a], Bool)
filter' _  [] = ([], False)
filter' f [x] = if f x then ([], True) else ([x], False)
filter' f (y:xs) = case filter' f xs of
                    (xs', True)  -> (xs', f y)
                    (xs', False) -> if f y then (xs', True) else (y:xs', False)

使用标准函数

filter' f xs = filter (not.f) $ map fst $ filter (not.f.snd) $ zip xs $ tail xs ++ [last xs]

【讨论】:

    【解决方案2】:

    假设你有:

    disallowed :: Int -> bool
    -- A function that matches your example
    disallowed x = elem x [6, 10, 13, 17]
    

    你想要的只是

    import Data.List (tails)
    
    map head . filter (not . any disallowed . take 2) . filter (not . null) . tails $ [2..20]
    

    如果你想给它一个名字:

    filterWithTails :: ([a] -> Bool) -> [a] -> [a]
    filterWithTails f = map head . filter f . filter (not . null) . tails
    
    filterWithTails (not . any disallowed . take 2) [2..20]
    

    (not . any disallowed . take 2) 是在过滤时考虑列表的其余部分来过滤列表的方式。很难给出一个比组成它的函数的组合更好的名称。

    【讨论】:

      猜你喜欢
      • 2014-02-06
      • 2022-01-18
      • 2022-01-18
      • 2012-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多