[erlang-questions] Filtering hierarchical data structure

Stanislav Ledenev s.ledenev@REDACTED
Sat Jul 14 14:41:34 CEST 2018


Mikael, thank you very much for a hint!

After some reasoning I came up to this solution:

filter(List, Search) ->
     F = fun F({policy, I, _}) -> lists:member(I, Search);
             F({section, SI, C}) ->
                 R = lists:filtermap(F, C),
                 case R of
                     [] -> false;
                     _ -> {true, {section, SI, R}}
                 end;
             F({section, _, []}) -> false
         end,
     lists:filtermap(F, List).

It doesn't seem that it could be improved more.

On 14.07.2018 11:54, Mikael Pettersson wrote:
> On Fri, Jul 13, 2018 at 3:25 PM, Stanislav Ledenev <s.ledenev@REDACTED> wrote:
>> Hello,
>>
>> I am new to Erlang and functional programming (1-1.5 months) and have task:
>>
>> 1. Suppose we have hierarchical tree-like data structure:
>> L = [
>> {section, "id1", [
>> {section, "id1.1", [
>> {policy, "p1", "v1"},
>> {policy, "p2", "v2"}
>> ]},
>> {section, "id1.2", [
>> ]}
>> ]},
>> {section, "id2", [
>> {policy, "p3", "v3"}
>> ] },
>> {section, "id3", [
>> ] }
>> ]
>>
>> 2. List of some "section"'s with children elements any of which could be
>> another "section" with children or "policy" with name and value.
>>
>> 3. Also we have another list which contains identifiers of policies:
>> F = ["p1", "p3"].
>> 4. Now I need to write a function which takes lists L, F and returns list L2
>> such as L2 contains only those "section"'s which has "policies" wich Id
>> equals to those in F. Empty sections must be removed.
>>
>> For lists L and F result should be:
>> L2 = [
>> {section, "id1", [
>> {section, "id1.1", [
>> {policy, "p1", "v1"},
>> ]},
>> ]},
>> {section, "id2", [
>> {policy, "p3", "v3"}
>> ] },
>> ]
>>
>> 5. I have solution (please see below) but it seems to me not as good as
>> it can be and even little weird. I am sure that it could be improved
>> and done in proper way.
>> If anyone could give me any glimpse or advice I would appreciate.
>>
>> Source:
>> ---------------------------------------------------------------------------
>> main() ->
>>      L = [
>>              {section, "id1", [
>>                  {section, "id1.1", [
>>                      {policy, "p1", "v1"},
>>                      {policy, "p2", "v2"}
>>                  ]},
>>                  {section, "id1.2", [
>>                  ]}
>>              ]},
>>              {section, "id2", [
>>                  {policy, "p3", "v3"}
>>              ] },
>>              {section, "id3", [
>>              ] }
>>          ],
>>      %filter(L, ["p1", "p3"]).
>>      filter(L, ["p3"]).
>>
>> filter([H | T], Search) ->
>>      lists:flatten([filter(H, Search, []) | filter(T, Search, [])]).
>>
>> filter({section, I, C}, Search, _Acc) ->
>>      NewC = filter(C, Search, []),
>>      case NewC of
>>          [] -> [];
>>          _ -> {section, I, NewC}
>>      end;
>>
>> filter([{section, I, C} | T], Search, Acc) ->
>>      NewC = filter(C, Search, []),
>>      case NewC of
>>          [] -> filter(T, Search, Acc);
>>          _ -> filter(T, Search, [{section, I, NewC} | Acc])
>>      end;
>>
>> filter([{policy, I, V} | T], Search, Acc) ->
>>      case lists:member(I, Search) of
>>          true -> filter(T, Search, [{policy, I, V} | Acc]);
>>          false -> filter(T, Search, Acc)
>>      end;
>> filter([], _S, Acc) -> Acc.
> Just some high-level comments.
>
> - Your data is clearly layered (there are items which can be policies
> or sections, and sections in turn contain lists of items), but your
> filtering code conflates these and in turn gets confused as to what
> it's processing, hence the large number of cases in filter/3.  Also,
> your code would crash if the top-level lists starts with a policy, but
> accepts it elsewhere, which smells like a bug.
> - You roll your own logic for reassembling the filtered-out fragments,
> which gets unnecessarily fiddly, and in this case I think wrong (you
> reorder items).
> - Using lists:filtermap/2 would greatly simplify your code.




More information about the erlang-questions mailing list