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

时间:2018-11-11 15:02:53

标签: erlang

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

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

对于变化(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]) ].

此解决方案将仅返回不会失败条件的列表(它可以工作,但对于大输入而言确实很慢)。

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

1 个答案:

答案 0 :(得分: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检查时其前缀已经为false时生成列表:

variation(1, L) ->
    [ [Elem] || Elem <- L ];
variation(N, L) ->
    [ Init ++ [Last] || Init <- variation(N-1, L), check(Init), Last <- L].

如您所见,由于check(Init)发生在之前 Last <- L,因此Last仅在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].

也许值得,也许不值得……您需要对自己的东西进行基准测试以弄清这一点。