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

如何在Haskell中列出所有可能替换的项目?,haskell,Haskell,我的输入是一个任意列表,例如 ["a","b","c"] 还有另一个列表元素,比如说“z”。我希望输出看起来像: [["z","b","c"],["a","z","c"],["a","b","z"]] 我该怎么做 replace :: [a] -> a -> [[a]] replace [] _special = [] replace (x:xs) special = (special:xs) : map (x:) (replace xs special) 测试: 说

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

["a","b","c"]
还有另一个列表元素,比如说
“z”
。我希望输出看起来像:

[["z","b","c"],["a","z","c"],["a","b","z"]]
我该怎么做

replace :: [a] -> a -> [[a]]
replace []     _special = []
replace (x:xs) special  = (special:xs) : map (x:) (replace xs special)
测试:

说明:

我们希望生成所有列表,其中只有一个元素被
特殊的
元素替换

如果列表为空,则无法插入
special
,因此我们不返回任何选项

如果列表改为
x:xs
,一个选项是替换
x
并获得
special:xs
。其他选项可以通过递归方式计算,在尾部
xs
中插入
special
,最后在每个选项前面插入
x

测试:

说明:

我们希望生成所有列表,其中只有一个元素被
特殊的
元素替换

如果列表为空,则无法插入
special
,因此我们不返回任何选项


如果列表改为
x:xs
,一个选项是替换
x
并获得
special:xs
。其他选项可以通过递归地采取任何方式来计算,在尾部插入
special
,最后在每个前面插入
x
;你能做的最好的,渐进的,是

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
注:这仅适用于base 4.7.0.2或更高版本(GHC 7.8.4或更高版本)

使用
tail
而不是
dropLast
演示一种更干净的方法

这里棘手的部分隐藏在
inits
中,在最近的版本中,inits非常高效且懒惰

如果你真的想让这个操作快速,你必须放弃列表,而使用其他的表示法

import Data.Sequence

replace :: a -> Seq a -> Seq (Seq a)
replace x xs = mapWithIndex f xs
  where
    f i _ = update i x xs

没有有效的方法来处理列表;你能做的最好的,渐进的,是

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
注:这仅适用于base 4.7.0.2或更高版本(GHC 7.8.4或更高版本)

使用
tail
而不是
dropLast
演示一种更干净的方法

这里棘手的部分隐藏在
inits
中,在最近的版本中,inits非常高效且懒惰

如果你真的想让这个操作快速,你必须放弃列表,而使用其他的表示法

import Data.Sequence

replace :: a -> Seq a -> Seq (Seq a)
replace x xs = mapWithIndex f xs
  where
    f i _ = update i x xs

这看起来像是一个家庭作业问题,所以这个答案可能对您没有帮助,但我喜欢使用
数据列表中的
inits
tails
来解决这类问题

看看
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]
许多这类问题都是这些列表的三向压缩功能。例如,此问题的解决方案是:

[ a ++ "z" ++ b | (a,b) <- zip as bs ]

[a++“z”++b|(a,b)这看起来像是一个家庭作业问题,所以这个答案可能对您没有帮助,但我喜欢使用
数据列表中的
inits
tails
来解决这类问题

看看
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向zip功能。例如,解决此问题的方法是:

[ a ++ "z" ++ b | (a,b) <- zip as bs ]

[a++“z”++b|(a,b)为什么效率低下?在任何情况下,都必须复制替换元素之前的列表单元格,而元素之后的尾部可以与输入列表共享,解决方案就是这样做的。@D如果看起来是O(n^2),这是渐近最优的。我忽略了什么吗?还有更有效的方法吗?如果将
null
映射到结果列表上,则需要O(n^2)要计算。您可以使其更增量;最简单的方法是使用base 4.7.0.2或更高版本,将
inits
压缩为
tails
。为什么效率低下?在任何情况下,都必须复制替换元素之前的列表单元格,而在元素之后,tails可以与输入列表共享,解决方案就是这样做的。@dfeuer它看起来是O(n^2),这是渐近最优的。我忽略了什么吗?还有更有效的方法吗?如果你把
null
映射到结果列表上,它将需要O(n^2)来计算。你可以使它更递增;最简单的方法,使用base 4.7.0.2或更高版本,是用
尾部压缩
inits