Удалить нули из списка - Erlang

Как я могу удалить нули из этого списка, скажем, я получаю:

[{"некоторые","другие",[]},ноль,{{"еще","еще",[]},ноль,ноль}]

В конце концов я хотел бы извлечь только первые элементы из длинных кортежей и поместить их в список, например:

["еще немного"]


person Bran Gi    schedule 11.09.2013    source источник
comment
У вас есть кортежи в кортежах, и они различаются по длине. Это нормально?   -  person Berzemus    schedule 11.09.2013


Ответы (2)


Вы можете удалить нули из списка, используя такую ​​​​функцию:

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

Однако эта функция не удаляет нули внутри кортежей.

И вы можете использовать пару функций для извлечения каждого первого элемента, не являющегося кортежем, в вашем списке (например, строки «некоторые» и другие):

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

Обновлять. Чтобы удалить нули из вложенных кортежей, мы можем использовать такую ​​функцию:

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).
person sergeyz    schedule 11.09.2013
comment
2> Data1 = [{some,other,[]}, nil, {{more,somemore,[]}, nil, nil}]. [{some,other,[]},nil,{{more,somemore,[]},nil,nil}] 3› extract:filter_out_nils(Data1). [{некоторые,другие,[]},{{еще,еще,[]},ноль,ноль}] - person Bran Gi; 11.09.2013
comment
Он фильтрует только первый ноль в кортеже - person Bran Gi; 11.09.2013
comment
@BranGi Второй и третий нули в примере являются частью кортежа. Функция filter_out_nils просто удаляет нулевые атомы из исходного списка. Он не выполняет глубокое удаление. Хотя можно написать рекурсивную функцию, которая может удалять нули из кортежей (и вложенных кортежей). - person sergeyz; 11.09.2013
comment
@BranGi Я обновил логику для функции filter_out_nils. Теперь он удаляет нули из вложенных кортежей: pastebin.com/xUsahbHz - person sergeyz; 11.09.2013

Отфильтровать 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, обратите внимание, что это решение не будет работать непосредственно в оболочке. Действительно, рекурсивные функции в оболочке должны быть записаны как функции, принимающие функцию (саму себя) в качестве аргумента (см.: Как написать рекурсивное веселье на 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. Это приведет к сбою, если аргумент не является правильным списком.

person Paul Guyot    schedule 11.09.2013