在haskell中按索引删除元素

时间:2009-11-14 23:52:30

标签: list haskell

我是haskell的新手,我正在寻找一些标准函数来处理索引列表。

我的确切问题是我想在每5个之后删除3个元素。如果它不够清楚这里是插图:

OOOOOXXXOOOOOXXX...

我知道如何使用许多参数编写庞大的函数,但是有没有聪明的方法可以做到这一点?

8 个答案:

答案 0 :(得分:15)

两种完全不同的方法

  1. 您可以将List.splitAtdrop一起使用:

    import Data.List (splitAt)
    f :: [a] -> [a]
    f [] = []
    f xs = let (h, t) = splitAt 5 xs in h ++ f (drop 3 t)
    

    现在f [1..12]会产生[1,2,3,4,5,9,10,11,12]。请注意,使用uncurryControl.Arrow.second

    可以更优雅地表达此功能
    import Data.List (splitAt)
    import Control.Arrow (second)
    f :: [a] -> [a]
    f [] = []
    f xs = uncurry (++) $ second (f . drop 3) $ splitAt 5 xs
    

    由于我们仍在使用Control.Arrow,我们可以选择放弃splitAt,而是在Control.Arrow.(&&&)的帮助下与take结合使用:

    import Control.Arrow ((&&&))
    f :: [a] -> [a]
    f [] = []
    f xs = uncurry (++) $ (take 5 &&& (f . drop 8)) xs
    

    但现在很明显,更简单的解决方案如下:

    f :: [a] -> [a] 
    f [] = []
    f xs = take 5 xs ++ (f . drop 8) xs
    

    Chris Lutz所述,此解决方案可以概括如下:

    nofm :: Int -> Int -> [a] -> [a]
    nofm _ _ [] = []
    nofm n m xs = take n xs ++ (nofm n m . drop m) xs
    

    现在nofm 5 8产生了所需的功能。 请注意,使用splitAt的解决方案可能仍然更有效!

  2. 使用mapsndfiltermodzip来应用一些数学:

    f :: [a] -> [a]
    f = map snd . filter (\(i, _) -> i `mod` 8 < (5 :: Int)) . zip [0..]
    

    这里的想法是我们将列表中的每个元素与其索引,自然数 i 配对。然后我们删除那些 i%8&gt;的元素。 4 。此解决方案的一般版本是:

    nofm :: Int -> Int -> [a] -> [a]
    nofm n m = map snd . filter (\(i, _) -> i `mod` m < n) . zip [0..]
    

答案 1 :(得分:6)

这是我的看法:

 $sql_string="SELECT id,keyword_tags,topic_name,contents,
                MATCH(keyword_tags) AGAINST ('$keysearch' IN BOOLEAN MODE) AS score1,
                MATCH(topic_name) AGAINST ('$keysearch' IN BOOLEAN MODE) AS score2,
                MATCH(contents) AGAINST ('$keysearch' IN BOOLEAN MODE) AS score3
                FROM ".$table_get." WHERE
                (MATCH(keyword_tags) AGAINST ('$keysearch' IN BOOLEAN MODE) OR
                MATCH(topic_name) AGAINST ('$keysearch' IN BOOLEAN MODE) OR
                MATCH(contents) AGAINST ('$keysearch' IN BOOLEAN MODE))
                AND id='1'
                ORDER BY score1 DESC, score2 DESC, score3 DESC LIMIT 1";

答案 2 :(得分:4)

您可以轻松统计您的元素:

strip' (x:xs) n | n == 7 = strip' xs 0
                | n >= 5 = strip' xs (n+1)
                | n < 5 = x : strip' xs (n+1)
strip l = strip' l 0

虽然开放式编码看起来更短:

strip (a:b:c:d:e:_:_:_:xs) = a:b:c:d:e:strip xs
strip (a:b:c:d:e:xs) = a:b:c:d:e:[]
strip xs = xs

答案 3 :(得分:4)

由于没有人使用“展开”版本,所以这是我的看法:

drop3after5 lst = concat $ unfoldr chunk lst
  where
    chunk [] = Nothing
    chunk lst = Just (take 5 lst, drop (5+3) lst)

似乎是迄今为止最短的

答案 4 :(得分:1)

takedrop函数可以在这里为您提供帮助。

drop, take :: Int -> [a] -> [a]

从这些我们可以构建一个函数来做一步。

takeNdropM :: Int -> Int -> [a] -> ([a], [a])
takeNdropM n m list = (take n list, drop (n+m) list)

然后我们可以用它来减少我们的问题

takeEveryNafterEveryM :: Int -> Int -> [a] -> [a]
takeEveryNafterEveryM n m [] = []
takeEveryNafterEveryM n m list = taken ++ takeEveryNafterEveryM n m rest
    where
        (taken, rest) = takeNdropM n m list

*Main> takeEveryNafterEveryM 5 3 [1..20]
[1,2,3,4,5,9,10,11,12,13,17,18,19,20]

因为这不是递归的原始形式,所以很难将其表达为简单的折叠。

因此可以定义新的折叠功能以满足您的需求

splitReduce :: ([a] -> ([a], [a])) -> [a] -> [a]
splitReduce f []   = []
splitReduce f list = left ++ splitReduce f right
    where
        (left, right) = f list

然后takeEveryNafterEveryM的定义就是

takeEveryNafterEveryM2 n m = splitReduce (takeNdropM 5 3)

答案 5 :(得分:1)

这是我的解决方案。它与@barkmadley's answer非常相似,仅使用takedrop,但在我看来不那么混乱:

takedrop :: Int -> Int -> [a] -> [a]
takedrop _ _ [] = []
takedrop n m l  = take n l ++ takedrop n m (drop (n + m) l)

不确定它是否会因速度或聪明而获奖,但我认为它非常简洁明了,而且确实有效:

*Main> takedrop 5 3 [1..20]
[1,2,3,4,5,9,10,11,12,13,17,18,19,20]
*Main> 

答案 6 :(得分:1)

myRemove = map snd . filter fst . zip (cycle $ (replicate 5 True) ++ (replicate 3 False))

答案 7 :(得分:0)

这是我的解决方案:

remElements step num=rem' step num
    where rem' _ _ []=[]
          rem' s n (x:xs)
              |s>0 = x:rem' (s-1) num xs
              |n==0 = x:rem' (step-1) num xs
              |otherwise= rem' 0 (n-1) xs

示例:

*Main> remElements 5 3 [1..20]
[1,2,3,4,5,9,10,11,12,13,17,18,19,20]