在列表中的每n个元素之后插入特定元素y

时间:2012-09-30 07:39:55

标签: haskell functional-programming

我正在自学Haskell,我在书中遇到了一个问题,要求我定义一个函数插入,它带有一个正整数n,元素y和一个列表{ {1}}在列表中的每个xs元素之后插入指定的元素y

我相信模式匹配可能是一个很好的方法,但我还没有真正理解它的含义

n

该功能应如何运作的一个例子:

insert :: Int -> Char -> [a] -> [a]
insert 0 y xs = xs
insert n y [] = []
insert n y (x:xs)

此时我已经处理了基本案例,但我不知道如何从这里开始。

有什么想法吗?感谢

4 个答案:

答案 0 :(得分:4)

在最后一种情况下,取n个列表元素,插入y的单个列表,然后在删除列表的前n个元素后追加调用函数的结果。

insert :: Int -> Char -> [a] -> [a]
insert 0 y xs = xs
insert n y [] = []
insert n y xs
 | length xs < n = xs
 | otherwise = take n xs ++ [y] ++ insert n y (drop n xs)

答案 1 :(得分:3)

你可以编写一个辅助函数,当它变为零时倒计时并重置。

insert :: Int -> a -> [a] -> [a]
insert n y xs = countdown n xs where
   countdown 0 xs = y:countdown n xs -- reset to original n
   countdown _ [] = []
   countdown m (x:xs) = x:countdown (m-1) xs

如果是时候插入,你想要什么行为? 在此,我通过在countdown 0 xs之前添加countdown _ []来优先插入完成。 如果你想在最后跳过插入,你怎么能重写呢?

样本用法:

*Main> insert 3 '|' "Hello Mum, erm... can I borrow £20000 please?"
"Hel|lo |Mum|, e|rm.|.. |can| I |bor|row| £2|000|0 p|lea|se?|"

答案 2 :(得分:3)

可以使用库函数。

import Data.List

insertAtN n y xs = intercalate [y] . groups n $ xs
  where
    groups n xs = takeWhile (not.null) . unfoldr (Just . splitAt n) $ xs

当然,如果您将Char插入到[a]类型的列表中,那么a就是Char,因为在Haskell中,列表的所有元素都是相同的类型。


为了帮助您更直接地理解这一点,让我们首先看一下列表的副本:

copyList (x:xs) = x : copyList xs
copyList [] = []

现在假设您为要复制的每个元素添加索引值(重新实现zip xs [1..]):

copyIdxList xs = go 1 xs where
  go i (x:xs) = (x,i) : go (i+1) xs
  go _ [] = []

现在我们在处理每个元素时有一个索引值,我们可以使用它,比如说,将列表的每个第10个元素放入结果中: p>

copyIdxTenthTwice xs = go 1 xs where
  go i (x:xs) | i==10 = (x,i) : (x,i) : go 1 xs
  go i (x:xs)         = (x,i) : go (i+1) xs
  go _ [] = []

看看我要去哪里?您可以在那里插入x,而不是复制y。而且您不必将索引放入结果中。

答案 3 :(得分:1)

ins n y xs = zip xs (cycle [1..n]) >>= f where
  f (x,k) = if k == n then [x,y] else [x] 

zip部分将循环“索引”附加到列表的元素,例如对于n = 3xs = "abcdefg",我们得到[('a',1),('b',2)('c',3)('d',1)('e',2)('f',3)('g',1)]。现在(>>=)(在列表的情况下与concatMap相同)使用f将每一对映射回原始元素,除非我们有一个循环的最后一个索引:在这种情况下,我们还插入了一个额外的分隔符元素y