从列表中删除 nil - Erlang

Posted

技术标签:

【中文标题】从列表中删除 nil - Erlang【英文标题】:Remove nils from a list - Erlang 【发布时间】:2013-09-15 11:27:11 【问题描述】:

我怎样才能从这个列表中删除 nils,假设我得到了:

["some","other",[],nil,"more","somemore",[],nil,nil]

最后我只想从长元组中提取第一个元素并将它们放在一个列表中, 比如:

[“一些”,“更多”]

【问题讨论】:

元组中有元组,它们的长度不同。这正常吗? 【参考方案1】:

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

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

虽然这个函数不会删除元组中的空值。

您可以使用几个函数来提取列表中的每个第一个非元组元素(例如字符串“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

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

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).

【讨论】:

2> Data1 = ["some","other",[], nil, "more","somemore",[], nil, nil]。 ["some","other",[],nil,"more","somemore",[],nil,nil] 3> 提取:filter_out_nils(Data1)。 ["some","other",[],"more","somemore",[],nil,nil] 它只过滤元组中的第一个 nil @BranGi 示例中的第二个和第三个 nil 是元组的一部分。函数filter_out_nils 只是从原始列表中删除“nil”原子。它不执行“深度删除”。尽管可以编写可以从元组(和嵌套元组)中删除 nil 的递归函数。 @BranGi 我已经更新了filter_out_nils 函数的逻辑。它现在从嵌套元组中删除 nil:pastebin.com/xUsahbHz【参考方案2】:

在您的示例中过滤掉 nil 并获取嵌套元组的第一个元素可以使用单个递归函数来实现,nil 案例的子句

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, []).

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

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

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

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

【讨论】:

以上是关于从列表中删除 nil - Erlang的主要内容,如果未能解决你的问题,请参考以下文章

从核心数据中删除/添加到核心数据后,带有列表的 SwiftUI TabView 不刷新

如何从 NSMutableArray 中删除 nil 对象?

Lua键从列表中返回项目为零

如何使用 NSPredicate 从 CoreData 中删除选定数量的行?

右手Redis(快速入门)

RestKit - 从 RKRequestDescriptor 中排除具有 nil 值的属性映射