如何在Haskell中列出所有可能替换的项目?

时间:2015-09-04 14:58:12

标签: haskell

我的输入是一个任意列表,例如

["a","b","c"]

和另一个列表元素,比如"z"。我希望输出看起来像:

[["z","b","c"],["a","z","c"],["a","b","z"]]

我该怎么做?

3 个答案:

答案 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中的tailsData.List解决这些问题。

了解initstail .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 ]

请注意,即使asbs长一个,zip也会遍历正确数量的元素。