如果子列表检查失败,列表理解将停止生成某些列表

List comprehension stop generating certain lists if sublist fails on check

我有一个代码,可以生成所有可能的变化(长度为 N)并重复。

variation(1, L) ->
    [ [H] || H <- L ];
variation(N, L) ->
    [[H | T] || H <- L, T <- variation(N - 1, L)].

对于 variation(3, [1,2,3,4]) 它将生成:

[[1,1,1,1],[1,1,1,2],[1,1,1,3],[1,1,1,4],[1,1 ,2,1],...]

我想在生成列表的过程中检查一个条件。如果子列表失败,它应该停止生成以特定子列表开头的列表。 例如,如果 [1,1] 子列表未通过该条件(检查),则它不应生成 [1,1,1,1]、[1,1,1,2] 等(所有以 [1 ,1]).

我不知道 1 个列表理解是否可行。 到目前为止,我有这个代码:

variation(1, L) ->
    [ [H] || H <- L ];
variation(N, L) ->
    [[H | T] || H <- L, T <- variation(N - 1, L), check([H|T]) ].

此解决方案只会 return 那些不满足条件的列表(它有效,但对于大输入来说真的很慢)。

如果 [1,1] 失败,它将尝试生成 [1,1,1,2],但这些也将无法通过检查。我需要一个解决方案,它不会尝试生成以 [1,1,...](或以前失败的子列表)开头的列表。

先说一个小细节:根据你的问题,variations(3, [1,2,3]).应该生成[[1,1,1,1], [1,1,1,2], …],但实际上生成了[[1,1,1], [1,1,2], …]。我假设代码是正确的,你的意思是说 variations(4, [1,2,3]). 应该生成 [[1,1,1,1], [1,1,1,2], …]

我写了一个你的函数的替代版本,在 LC 的右侧使用不同的顺序,避免在使用 check/1:

检查前缀已经为假时生成列表
variation(1, L) ->
    [ [Elem] || Elem <- L ];
variation(N, L) ->
    [ Init ++ [Last] || Init <- variation(N-1, L), check(Init), Last <- L].

如您所见,由于 check(Init) 发生在 之前 Last <- LLast 仅在 check(Init) == true 时生成。 这可能会产生您想要的效果。

但是……要小心。我在 LC 的左侧使用 ++。你绝对应该对你的代码进行基准测试,看看它是否对性能有影响。

如果是,并且仅当它是,您可能需要考虑使用这样的东西:

variation3(1, L) ->
    [ [Elem] || Elem <- L ];
variation3(N, L) ->
    [ lists:reverse([Last|lists:reverse(Init)]) || Init <- variation2(N-1, L), check(Init), Last <- L].

也许值得,也许不……你需要对你的东西进行基准测试才能弄明白。