Search code examples
erlangfoldets

Erlang ets remove / filter element


I use elang ets table as a simple cache. I want to use a process to scan the table and remove expired elements (multiple).

with ets:foldl

expire_table_example() ->
Tab = ets:new(ets_tab, [named_table, set]),
ets:insert(Tab, [{a, 1}, {b, 2}, {c, 3}, {d, 4}, {e, 5},{f,7}]),
Tab1 = ets:foldl(fun({Key, Val}, Acc) ->
if
   (Val > 3) -> [{Key, Val} | Acc];
   true -> Acc
 end
end, Tab, Tab),
io:format("end ~p ~n", [Tab1]).

I got

[{f,7},{e,5},{d,4}|ets_tab] %% the ets_tab is NOT expected.

How Can I fix This?

Any other API's would do this better?


Solution

  • You can't use ets table as accumulator.

    For your purpose you can use ets:select_delete/2:

    1> Tab = ets:new(ets_tab, [named_table, set]).
    ets_tab
    2> ets:insert(Tab, [{a, 1}, {b, 2}, {c, 3}, {d, 4}, {e, 5},{f,7}]).
    true
    3> ets:select_delete(Tab, [{{'$1','$2'},[{'=<','$2',3}],[true]}]).
    3
    4> ets:tab2list(Tab).
    [{f,7},{e,5},{d,4}]
    

    Or you can use ets:tab2list/1 to get list of all values, filter them and after that re-insert to table:

    1> Tab = ets:new(ets_tab, [named_table, set]).
    ets_tab
    2> ets:insert(Tab, [{a, 1}, {b, 2}, {c, 3}, {d, 4}, {e, 5},{f,7}]).
    true
    3> L = ets:tab2list(Tab).
    [{f,7},{e,5},{d,4},{c,3},{b,2},{a,1}]
    4> L2 = lists:filter(fun({Key,Val}) -> Val > 3 end, L).
    [{f,7},{e,5},{d,4}]
    5> ets:delete_all_objects(Tab).
    true
    6> ets:insert(Tab, L2).
    true
    7> ets:tab2list(Tab).
    [{f,7},{e,5},{d,4}]