【问题标题】:Remove every nth element from string从字符串中删除每个第 n 个元素
【发布时间】:2011-07-14 10:12:39
【问题描述】:

如何删除字符串的每个第 n 个元素?

我猜你会以某种方式使用drop 函数。

像这样丢弃第一个 n,你怎么能改变它,只丢弃第 n 个,然后是之后的第 n 个,依此类推,而不是全部?

dropthem n xs = drop n xs

【问题讨论】:

    标签: haskell


    【解决方案1】:

    我喜欢以下解决方案:

    del_every_nth :: Int -> [a] -> [a]    
    del_every_nth n = concat . map init . group n 
    

    您只需要定义一个函数group,它将一个列表分组为长度为n 的部分。但这很容易:

    group :: Int -> [a] -> [[a]]
    group n [] = []
    group n xs = take n xs : group n (drop n xs)
    

    【讨论】:

    • hlint 建议使用concatMap 而不是concat . map
    【解决方案2】:
    remove_every_nth :: Int -> [a] -> [a]
    remove_every_nth n = foldr step [] . zip [1..]
        where step (i,x) acc = if (i `mod` n) == 0 then acc else x:acc

    函数的作用如下:

    zip [1..] 用于索引列表中的所有项目,例如zip [1..] "foo" 变为 [(1,'f'), (2,'o'), (3,'o')]

    然后使用right fold 处理索引列表,该right fold 会累积索引不能被n 整除的每个元素。

    这里有一个稍长的版本,基本上做同样的事情,但避免了来自zip [1..] 的额外内存分配,并且不需要计算模数。

    remove_every_nth :: Int -> [a] -> [a]
    remove_every_nth = recur 1
        where recur _ _ []     = []
              recur i n (x:xs) = if i == n
                then recur 1 n xs
                else x:recur (i+1) n xs

    【讨论】:

    • 与其略贵的zipmod,不如用cycle[1..n]和1比较?
    • remove_every_nth n = map snd . filter ((/= 0) . (`mod` n) . fst) . zip [1..]
    • @Peaker:感谢您的建议。我不确定如果不使用zip,您将如何使用cycle,但我以不同的方式提高了效率。
    • cycle: removeEveryNth n = map snd . filter ((/= n) . fst) . (zip $ cycle [1..n])
    • 另一种变体:\n l -> catMaybes $ zipWith (flip id) l $ cycle $ replicate (n-1) Just ++ [const Nothing]
    【解决方案3】:

    简单。取 (n-1) 个元素,然后跳过 1 个,冲洗并重复。

    dropEvery _ [] = []
    dropEvery n xs = take (n-1) xs ++ dropEvery n (drop n xs)
    

    为了效率,还是采用showS风格

    dropEvery n xs = dropEvery' n xs $ []
        where dropEvery' n [] = id
              dropEvery' n xs = (take (n-1) xs ++) . dropEvery n (drop n xs)
    

    【讨论】:

      【解决方案4】:
      -- groups is a pretty useful function on its own!
      groups :: Int -> [a] -> [[a]]
      groups n = map (take n) . takeWhile (not . null) . iterate (drop n)
      
      removeEveryNth :: Int -> [a] -> [a]
      removeEveryNth n = concatMap (take (n-1)) . groups n
      

      【讨论】:

        【解决方案5】:

        尝试结合takedrop 来实现这一点。

        take 3 "hello world" = "hel"
        drop 4 "hello world" = "o world"
        

        【讨论】:

        • 我在我的帖子中犯了一个错误,我现在得到了这个,它从我的列表中删除了第 n 个值。我想从列表中删除每个第 n 个值,所以我猜我需要添加一些递归?还是过滤器?
        • @Lunar,你说的“每n个值”是什么意思?
        • eg: 4 "thisiscool" 将给 "thiiscol" 从字符串中删除每 4 个元素
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多