我的输入是一个任意列表,例如
["a","b","c"]
和另一个列表元素,比如"z"
。我希望输出看起来像:
[["z","b","c"],["a","z","c"],["a","b","z"]]
我该怎么做?
答案 0 :(得分:7)
replace :: [a] -> a -> [[a]]
replace [] _special = []
replace (x:xs) special = (special:xs) : map (x:) (replace xs special)
测试:
> replace ["a","b","c"] "z"
[["z","b","c"],["a","z","c"],["a","b","z"]]
说明:
我们希望生成所有列表,其中只有一个元素被special
替换。
如果列表为空,则无法插入special
,因此我们不会返回选项。
如果列表是x:xs
,则一个选项是替换x
并获取special:xs
。可以通过递归地采用任何方式在尾部special
中插入xs
来计算其他选项,并最终在每个选项前面添加x
。
答案 1 :(得分:5)
使用列表没有有效的方法;渐渐地,你能做的最好的事情就是
replace x xs = zipWith f (inits xs) (dropLast $ tails xs)
where
f front (_ : rear) = front ++ x : rear
dropLast [] = []
dropLast [_] = []
dropLast (x:xs) = x : dropLast xs
注意:对于基础4.7.0.2或更高版本(GHC 7.8.4或更高版本),这只是相当有效。
https://stackoverflow.com/a/32402969/1477667使用tail
代替dropLast
演示了更简洁的方式。
这里棘手的部分隐藏在inits
中,在最近的版本中,它们非常有效且既懒又合理。
如果您真的想快速完成此操作,则必须放弃列表并使用其他表示形式。
import Data.Sequence
replace :: a -> Seq a -> Seq (Seq a)
replace x xs = mapWithIndex f xs
where
f i _ = update i x xs
答案 2 :(得分:5)
这看起来像是一个家庭作业问题所以这个答案可能对您没有帮助,但我喜欢使用inits
中的tails
和Data.List
解决这些问题。
了解inits
和tail .tails
的工作原理:
as = inits [1..3] = [ [], [1], [1,2], [1,2,3] ]
bs = tail (tails [1..3]) = [ [2,3], [3], [] ]
cs = [1..3] = [ 1, 2, 3]
这些问题中的许多都是这些列表的3向拉链的功能。例如,这个问题的解决方案是:
[ a ++ "z" ++ b | (a,b) <- zip as bs ]
或者,如果您需要为每个元素添加1:
[ a ++ [c+1] ++ b | (a,b,c) <- zip3 as bs cs ]
或删除每个元素:
[ a ++ b | (a,b) <- zip as bs ]
请注意,即使as
比bs
长一个,zip也会遍历正确数量的元素。