[英]Erlang for each list of lists
我想創建一個僅包含長度為1的“列表列表”元素的新列表。
我提供的代碼給出了異常錯誤:沒有匹配的功能子句。
lists:foreach(fun(X) if length(X) =:= 1 -> [X] end, ListOfLists).
我是erlang的新手,我很難找到另一種編寫這段代碼的方法。
有人可以給我一些建議嗎?
您可以匹配列表理解來自然地做到這一點:
[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
,然后測試結果需要遍歷整個列表,返回一個值,然后對其進行測試。 這比檢查列表的第二個元素是否為終止符(換句話說,數據的“形狀”是否匹配)要大得多。
關於您上面的嘗試...
作為Erlang的新手,熟悉基本的功能列表操作可能會有所幫助。 它們在功能(和邏輯)編程中一遍又一遍地彈出,並且通常具有相同的名稱。 “地圖”,“折疊”,“過濾器”,“缺點”,“汽車”(“頭”或“ hd”或[X|_]
),“ cdr”(“尾巴”或“ tl”或[_|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).
實際上,我並不關心返回值,並且我們也不會更改“ Users
或“ Message
”列表中的任何Message
。 (請注意,這里我們使用匿名函數捕獲所需的相關狀態 -本質上是計算出Message
值,因此我們可以將arity 1函數呈現給foreach/2
的列表操作。這是lambda變得最有用的地方在Erlang與命名函數中。)
當您希望將列表作為輸入並返回單個匯總值(使用某些操作將列表中的所有值都滾動為一個)時,可以使用fold(幾乎總是想使用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
的調用中內聯作為匿名函數。
但是,您真正要執行的操作是過濾列表,並且有一個通用的列表函數叫做。 您提供了一個返回布爾值的測試函數-如果測試為true,則該元素將在輸出中出現,否則它將不會:
5> lists:filter(fun([X]) -> true; (_) -> false end, LoL).
[[a],[e]]
像以前一樣將lambda分解:
6> Single =
6> fun([X]) -> true;
6> (_) -> false
6> end.
#Fun<erl_eval.6.54118792>
7> lists:filter(Single, LoL).
[[a],[e]]
在這里,我們在匿名函數頭中匹配了元素的形狀。 這個過濾器幾乎完全等同於上面的列表理解(實際上唯一的區別是列表理解的底層實現-從語義上講它們是相同的)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.