每个列表列表的Erlang

时间:2015-12-05 09:54:14

标签: list foreach erlang

我想创建一个新列表,其中只包含长度为1的“列表列表”的元素。

我提供的代码给出了一个异常错误:没有函数子句匹配。

lists:foreach(fun(X) if length(X) =:= 1 -> [X] end, ListOfLists).

我是erlang的新手,我很难找到另一种编写这段代码的方法。

有人可以就如何这样做给我一些建议吗?

1 个答案:

答案 0 :(得分:6)

你可以在列表理解中匹配,以便很自然地得到这个:

[L || L = [_] <- ListOfLists]

例如:

1> LoL = [[a], [b,c], d, [e], [f,g]].
[[a],[b,c],d,[e],[f,g]]
2> [L || L = [_] <- LoL].
[[a],[e]]

如果您想要元素本身(如结果[a, e]而不是[[a], [e]]),您可以匹配形状中的元素:

3> [L || [L] <- LoL].    
[a,e]

根据LoL中包含的列表的大小,匹配将比在每个成员上调用length/1快得多。调用length/1然后测试结果需要遍历整个列表,返回一个值,然后测试它。这比检查列表的第二个元素是否是终止(换句话说,如果数据的&#34;形状&#34;是否匹配)任意更多的开销。

关于您的上述尝试......

作为Erlang的新手,熟悉基本功能列表操作可能会有所帮助。它们在功能(和逻辑)编程中反复弹出,并且通常具有相同的名称。 &#34;地图&#34;,&#34;折叠&#34;,&#34;过滤器&#34;,&#34; cons&#34;,&#34; car&#34; (&#34; head&#34;或&#34; hd&#34;或[X|_]),&#34; cdr&#34; (&#34; tail&#34;或&#34; tl&#34;或[_|X]),依此类推。

您最初的尝试:

lists:foreach(fun(X) if length(X) =:= 1 -> [X] end, ListOfLists).

这不起作用,因为foreach/2只会返回ok,而不会返回任何值。如果要迭代列表以获取副作用,则仅使用 ,而不是因为您希望获得返回值。例如,如果我有一个聊天系统,聊天室会有一个当前成员列表,并且广播消息实际上是将每个聊天消息发送给列表中的每个成员,我可能会这样做:

-spec broadcast(list(), unicode:chardata()) -> ok.
broadcast(Users, Message) ->
    Forward = fun(User) -> send(User, Message) end,
    lists:foreach(Forward, Users).

我真的不关心返回值,我们也无法更改列表UsersMessage中的任何内容。 (注意,这里我们使用匿名函数来捕获它所需的相关状态 - 基本上清除了Message值,这样我们就可以向列表操作提供arity 1的函数foreach/2。这是lambda在Erlang和命名函数中最有用的地方。)

如果要将列表作为输入并返回单个聚合值(使用某些操作将列表中的所有值都滚动到一个),您可以使用折叠(您几乎总是想要使用{{1 ,具体而言):

foldl/3

分解为:

4> lists:foldl(fun(X, A) when length(X) =:= 1 -> [X|A]; (_, A) -> A end, [], LoL).
[[e],[a]]

这是一个匿名函数,有两个子句。

用我们可以做的案例写另一种方式:

Single =
    fun
        (X, A) when length(X) =:= 1 -> [X|A];
        (_, A) -> [X|A]
    end,
ListOfSingles = lists:foldl(Single, [], LoL).

这是一个偏好问题,因为可以选择将其作为Single = fun(X, A) -> case length(X) of 1 -> [X|A]; _ -> A end end, 调用中的匿名函数。

真正试图做的是过滤列表,并且有一个通用列表函数就是这样。你提供了一个返回布尔值的测试函数 - 如果测试为真,那么元素将在输出中出现,否则它将不会:

foldl/3

像以前一样打破lambda:

5> lists:filter(fun([X]) -> true; (_) -> false end, LoL).
[[a],[e]]

这里我们匹配匿名函数头中元素的形状。这个过滤器几乎完全等同于上面的列表推导(唯一的区别,实际上,在列表推导的底层实现中 - 在语义上它们是相同的)。