从列表中删除nils - Erlang

时间:2013-09-11 12:25:18

标签: functional-programming erlang ejabberd otp erlang-shell

如何从此列表中删除nils,假设我得到:

[{ “一些”, “其它”,[]},零,{{ “多”, “somemore”,[]},零,零}]

最后,我想从长元组中仅提取第一个元素并将它们放在列表中, 类似的东西:

[“some”,“more”]

2 个答案:

答案 0 :(得分:2)

您可以使用以下函数从列表中删除nils:

filter_out_nils(Data) when is_list(Data) ->
    Pred = fun(Element) -> Element /= nil end,
    lists:filter(Pred, Data). 

此函数不会删除元组中的nils。

你可以使用几个函数来提取列表中的每个第一个非元组元素(比如字符串“some”和更多):

extract_first_elements(Data) when is_list(Data) ->
    lists:map(fun extract_first_non_tuple_element/1, Data).

extract_first_non_tuple_element({})-> {};
extract_first_non_tuple_element(Data) when is_tuple(Data)-> 
    case element(1, Data) of
        First when is_tuple(First) -> extract_first_non_tuple_element(First);
        Other -> Other
    end.

函数extract_first_non_tuple_element是递归的,因为在你的示例中,元组可以嵌套。

所以要测试这个功能:

Data1 = [{"some","other",[]}, nil, {{"more","somemore",[]}, nil, nil}].
filter_out_nils(Data1).
[{"some","other",[]},{{"more","somemore",[]},nil,nil}] % resulting list without nils
Data2 = extract_first_elements(Data1).
["some","more"] % extracted first elements

更新。 要从嵌套元组中删除nils,我们可以使用如下函数:

filter_out_nils_from_tuple(Data) when is_tuple(Data) ->
    TList = tuple_to_list(Data),
    Fun = fun(Element, Acc) ->
        case Element of
            nil -> Acc;
            Tuple when is_tuple(Tuple) -> Acc ++ [filter_out_nils_from_tuple(Tuple)];
            Other -> Acc ++ [Other]
        end
    end,
    Result = lists:foldl(Fun, [], TList),
    list_to_tuple(Result).

答案 1 :(得分:1)

使用单个递归函数过滤掉nils并获取示例中嵌套元组的第一个元素, nil case 的子句:

f([Item  | T], Acc) when is_tuple(Item) -> f([element(1, Item) | T], Acc);
f([nil   | T], Acc) -> f(T, Acc); % filter out nil
f([Other | T], Acc) -> f(T, [Other | Acc]);
f([], Acc) -> lists:reverse(Acc).

由于您添加了erlang-shell标记,请注意此解决方案无法直接在shell中使用。实际上,shell中的递归函数应该被写为函数(自身)作为参数(参见:How do you write a fun that's recursive in Erlang?)。

F = fun(F, [Item  | T], Acc) when is_tuple(Item) ->
            F(F, [element(1, Item) | T], Acc);
       (F, [nil   | T], Acc) -> F(F, T, Acc);
       (F, [Other | T], Acc) -> F(F, T, [Other | Acc]);
       (_F, [], Acc) -> lists:reverse(Acc)
    end.
F(F, List, []).

另请注意,此解决方案针对您的问题中未涵盖的案例具有特定行为:

  1. 如果输入列表包含空元组,它将因函数子句错误而崩溃。然而,这可能是一种理想的行为。否则,您可以根据需要添加一个新的函数子句来处理它(如果过滤掉或返回空元组?)。

  2. 它将接受并返回列表中的非元组元素(nil除外),例如f(["some", "more"], [])。为避免这种情况,您需要稍微不同的逻辑。

  3. 如果参数不是正确的列表,它将崩溃。