列表推导加模式匹配

Posted

技术标签:

【中文标题】列表推导加模式匹配【英文标题】:list comprehensions plus pattern matching 【发布时间】:2018-10-30 02:10:20 【问题描述】:

我要解决的问题是:“查找列表 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】:

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

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]

【讨论】:

谢谢!第一个虽然效率低下,但确实展示了如何做我想做的事 - 但不是尝试一个无法工作的深奥生成器,而是你做 2 个简单的生成器

以上是关于列表推导加模式匹配的主要内容,如果未能解决你的问题,请参考以下文章

什么是KMP算法?KMP算法推导

Elixir 列表模式匹配 ~ 在使用列表模式匹配常量后得到 x

Python中列表的模式匹配

在erlang中列出尾部模式匹配

使用模式匹配交换列表中的元素对

如何改进 Python 中列表的模式匹配