Haskell 列表理解创建所有可能的值组合
Haskell list comprehension creating all possible combinations of values
我想创建一个列表列表,其中包含大小为 n
的较小列表中所有可能的值组合
例如,假设我有列表 [1,2,3],并且 n 等于 2。
输出将是:
[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[ 3,3]]
对于固定的 N 听起来很容易,但是对于不确定的 N 值它如何工作?
到目前为止我已经尝试过:
[[x,y] | x <- [1,2,3], y <- [1,2,3]]
这适用于固定为 2 的 n。但我不知道如何让它依赖于 N。
有一个库函数可以做到这一点:它是 Control.Monad
包中的 replicateM
:
> import Control.Monad
> replicateM 2 [1,2,3]
[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]]
> replicateM 5 [1,2,3]
[[1,1,1,1,1],[1,1,1,1,2],[1,1,1,1,3],[1,1,1,2,1],....]
但是,如果您有兴趣自己定义它,那么对于未确定的 N
使用单个列表推导式确实无法做到这一点是对的。相反,您需要编写一个递归版本。这个想法是,如果我们已经有了一些 n
的答案,比如 n=2
:
[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]]
然后我们可以通过在所有这些列表前加上第一个元素来生成下一个 n
(n=3
) 的答案:
[1,1,1],[1,1,2],[1,1,3],[1,2,1],[1,2,2],[1,2,3],[1,3,1],[1,3,2],[1,3,3]
与第二个和第三个元素类似:
[2,1,1],[2,1,2],[2,1,3],[2,2,1],[2,2,2],[2,2,3],[2,3,1],[2,3,2],[2,3,3]
[3,1,1],[3,1,2],[3,1,3],[3,2,1],[3,2,2],[3,2,3],[3,3,1],[3,3,2],[3,3,3]
生成完整的结果列表。
作为列表理解,它看起来像:
combos n lst = [x:xs | x <- lst, xs <- combos (n-1) lst]
我们还需要递归的基本情况。我们可以使用:
combos 0 lst = [[]]
完整的定义是:
combos :: Int -> [a] -> [[a]]
combos 0 lst = [[]]
combos n lst = [x:xs | x <- lst, xs <- combos (n-1) lst]
这按预期工作:
> combos 3 [1,2,3]
[[1,1,1],[1,1,2],[1,1,3],[1,2,1],[1,2,2],[1,2,3],[1,3,1],[1,3,2],[1,3,3]
,[2,1,1],[2,1,2],[2,1,3],[2,2,1],[2,2,2],[2,2,3],[2,3,1],[2,3,2],[2,3,3]
,[3,1,1],[3,1,2],[3,1,3],[3,2,1],[3,2,2],[3,2,3],[3,3,1],[3,3,2],[3,3,3]]
我想创建一个列表列表,其中包含大小为 n
的较小列表中所有可能的值组合例如,假设我有列表 [1,2,3],并且 n 等于 2。 输出将是: [[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[ 3,3]]
对于固定的 N 听起来很容易,但是对于不确定的 N 值它如何工作?
到目前为止我已经尝试过:
[[x,y] | x <- [1,2,3], y <- [1,2,3]]
这适用于固定为 2 的 n。但我不知道如何让它依赖于 N。
有一个库函数可以做到这一点:它是 Control.Monad
包中的 replicateM
:
> import Control.Monad
> replicateM 2 [1,2,3]
[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]]
> replicateM 5 [1,2,3]
[[1,1,1,1,1],[1,1,1,1,2],[1,1,1,1,3],[1,1,1,2,1],....]
但是,如果您有兴趣自己定义它,那么对于未确定的 N
使用单个列表推导式确实无法做到这一点是对的。相反,您需要编写一个递归版本。这个想法是,如果我们已经有了一些 n
的答案,比如 n=2
:
[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]]
然后我们可以通过在所有这些列表前加上第一个元素来生成下一个 n
(n=3
) 的答案:
[1,1,1],[1,1,2],[1,1,3],[1,2,1],[1,2,2],[1,2,3],[1,3,1],[1,3,2],[1,3,3]
与第二个和第三个元素类似:
[2,1,1],[2,1,2],[2,1,3],[2,2,1],[2,2,2],[2,2,3],[2,3,1],[2,3,2],[2,3,3]
[3,1,1],[3,1,2],[3,1,3],[3,2,1],[3,2,2],[3,2,3],[3,3,1],[3,3,2],[3,3,3]
生成完整的结果列表。
作为列表理解,它看起来像:
combos n lst = [x:xs | x <- lst, xs <- combos (n-1) lst]
我们还需要递归的基本情况。我们可以使用:
combos 0 lst = [[]]
完整的定义是:
combos :: Int -> [a] -> [[a]]
combos 0 lst = [[]]
combos n lst = [x:xs | x <- lst, xs <- combos (n-1) lst]
这按预期工作:
> combos 3 [1,2,3]
[[1,1,1],[1,1,2],[1,1,3],[1,2,1],[1,2,2],[1,2,3],[1,3,1],[1,3,2],[1,3,3]
,[2,1,1],[2,1,2],[2,1,3],[2,2,1],[2,2,2],[2,2,3],[2,3,1],[2,3,2],[2,3,3]
,[3,1,1],[3,1,2],[3,1,3],[3,2,1],[3,2,2],[3,2,3],[3,3,1],[3,3,2],[3,3,3]]