列表理解加模式匹配

时间:2018-05-20 04:06:48

标签: erlang pattern-matching list-comprehension

我试图解决的问题是:“找到列表L的所有元素,后面跟着值为X的元素。”

我试图使用列表理解来做到这一点。但是,我现在怀疑它是否可能。我理解事情应该在一个更简单的场景中工作,比如这个

[some_transformation(X) || X <- [...], some_conditional(X)].

Xs上有一个过滤器,它来自Xs的生成器,并且转换应用于那些通过的过滤器。

我的希望非常渺茫,因为Erlang的模式匹配能力允许这样的事情:

[H1|[H2|T]] = [1,2,3,4].

,它绑定H1和H2。是否有一些模式可以在列表理解中使用以实现所需的结果?

当我天真地尝试这个时,它显然不起作用:

78> [X||[H1|[H2|_]]=X <- [1,2,3,4]].
[]

也许我应该停止懒惰,并希望列表理解和模式匹配的魔力为我做所有的工作? = P

1 个答案:

答案 0 :(得分:3)

您可以使用列表尾部删除的最后一个元素压缩列表,然后使用list comprehension:

1> List = [1, 2, 3, 2, 1, 2, 2, 1, 1, 3, 1].
[1,2,3,2,1,2,2,1,1,3,1]
2> X = 1.
1
3> Zipped = lists:zip(lists:droplast(List), tl(List)).
[{1,2},
 {2,3},
 {3,2},
 {2,1},
 {1,2},
 {2,2},
 {2,1},
 {1,1},
 {1,3},
 {3,1}]
4> [A || {A, B} <- Zipped, B == X].
[2,2,1,3]

这样效率很低 - 它会创建列表的副本(对于droplast)和新的压缩列表。您可以使用这样的递归来提高效率:

-module(a).
-export([before/2]).

before(List, X) ->
  before(List, X, []).

before([A, X | Tail], X, Acc) ->
  before([X | Tail], X, [A | Acc]);
before([_ | Tail], X, Acc) ->
  before(Tail, X, Acc);
before([], _, Acc) ->
  lists:reverse(Acc).
1> c(a).
{ok,a}
2> a:before([1, 2, 3, 2, 1, 2, 2, 1, 1, 3, 1], 1).
[2,2,1,3]