<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p><tt>Yes, I've skipped this one. Thank you!</tt><br>
    </p>
    <br>
    <div class="moz-cite-prefix">On 14.07.2018 16:35, Dmitry Belyaev
      wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:1414AC57-C3F5-425D-BD09-1F06FCEDB976@gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=utf-8">
      You can improve it by removing the last clause<br>
      F({section, _, []}) -> false<br>
      <br>
      <br>
      <div class="gmail_quote">On 14 July 2018 22:41:34 GMT+10:00,
        Stanislav Ledenev <a class="moz-txt-link-rfc2396E" href="mailto:s.ledenev@gmail.com"><s.ledenev@gmail.com></a> wrote:
        <blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt
          0.8ex; border-left: 1px solid rgb(204, 204, 204);
          padding-left: 1ex;">
          <pre class="k9mail">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:
<blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;"> On Fri, Jul 13, 2018 at 3:25 PM, Stanislav Ledenev <a class="moz-txt-link-rfc2396E" href="mailto:s.ledenev@gmail.com"><s.ledenev@gmail.com></a> wrote:
<blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;"> 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:
<hr>
 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.
</blockquote> 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.
</blockquote>
<hr>
erlang-questions mailing list
<a class="moz-txt-link-abbreviated" href="mailto:erlang-questions@erlang.org">erlang-questions@erlang.org</a>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" moz-do-not-send="true">http://erlang.org/mailman/listinfo/erlang-questions</a>
</pre>
        </blockquote>
      </div>
      <br>
      -- <br>
      Kind regards,<br>
      Dmitry Belyaev
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <br>
      <pre wrap="">_______________________________________________
erlang-questions mailing list
<a class="moz-txt-link-abbreviated" href="mailto:erlang-questions@erlang.org">erlang-questions@erlang.org</a>
<a class="moz-txt-link-freetext" href="http://erlang.org/mailman/listinfo/erlang-questions">http://erlang.org/mailman/listinfo/erlang-questions</a>
</pre>
    </blockquote>
    <br>
    <pre class="moz-signature" cols="72">-- 
-- Stanislav Ledenev</pre>
  </body>
</html>