-module(counter). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([new/0, insert/2, get/2, keys/1, values/1, elements/1, update/2, add/2, subtract/2, unique_size/1, total/1, to_list/1, most_common/1, most_common_n/2, from_list/1, to_dict/1, from_dict/1]). -export_type([counter/1]). -opaque counter(OHQ) :: {counter, gleam@dict:dict(OHQ, integer())}. -spec new() -> counter(any()). new() -> {counter, gleam@dict:new()}. -spec insert(counter(OHT), OHT) -> counter(OHT). insert(Counter, Item) -> _pipe = erlang:element(2, Counter), _pipe@2 = gleam@dict:update( _pipe, Item, fun(Count) -> begin _pipe@1 = Count, gleam@option:unwrap(_pipe@1, 0) end + 1 end ), {counter, _pipe@2}. -spec get(counter(OHW), OHW) -> integer(). get(Counter, Item) -> _pipe = erlang:element(2, Counter), _pipe@1 = gleam@dict:get(_pipe, Item), gleam@result:unwrap(_pipe@1, 0). -spec keys(counter(OIE)) -> list(OIE). keys(Counter) -> _pipe = erlang:element(2, Counter), gleam@dict:keys(_pipe). -spec values(counter(any())) -> list(integer()). values(Counter) -> _pipe = erlang:element(2, Counter), gleam@dict:values(_pipe). -spec prepend_repeated_item(OIN, integer(), list(OIN)) -> list(OIN). prepend_repeated_item(Item, Times, Acc) -> gleam@bool:guard( Times =< 0, Acc, fun() -> prepend_repeated_item(Item, Times - 1, [Item | Acc]) end ). -spec elements(counter(OIK)) -> list(OIK). elements(Counter) -> _pipe = erlang:element(2, Counter), _pipe@1 = maps:to_list(_pipe), gleam@list:fold( _pipe@1, [], fun(Items, Item) -> prepend_repeated_item( erlang:element(1, Item), erlang:element(2, Item), Items ) end ). -spec update(counter(OIQ), list(OIQ)) -> counter(OIQ). update(Counter, Items) -> gleam@list:fold(Items, Counter, fun(Counter@1, Item) -> _pipe = Counter@1, insert(_pipe, Item) end). -spec add(counter(OIU), counter(OIU)) -> counter(OIU). add(Counter_1, Counter_2) -> _pipe = gleam@dict:combine( erlang:element(2, Counter_1), erlang:element(2, Counter_2), fun gleam@int:add/2 ), {counter, _pipe}. -spec subtract(counter(OIY), counter(OIY)) -> counter(OIY). subtract(Counter_1, Counter_2) -> Dict_1 = erlang:element(2, Counter_1), Dict_2 = erlang:element(2, Counter_2), Dict_2_exclusive = begin _pipe = Dict_2, gleam@dict:drop(_pipe, gleam@dict:keys(Dict_1)) end, Dict_2_overlap = begin _pipe@1 = Dict_2, gleam@dict:drop(_pipe@1, gleam@dict:keys(Dict_2_exclusive)) end, _pipe@2 = Dict_1, _pipe@3 = gleam@dict:combine( _pipe@2, Dict_2_overlap, fun gleam@int:subtract/2 ), _pipe@4 = gleam@dict:filter(_pipe@3, fun(_, B) -> B > 0 end), {counter, _pipe@4}. -spec unique_size(counter(any())) -> integer(). unique_size(Counter) -> _pipe = erlang:element(2, Counter), maps:size(_pipe). -spec total(counter(any())) -> integer(). total(Counter) -> _pipe = erlang:element(2, Counter), _pipe@1 = maps:to_list(_pipe), _pipe@2 = gleam@list:map(_pipe@1, fun gleam@pair:second/1), gleam@int:sum(_pipe@2). -spec to_list(counter(OJG)) -> list({OJG, integer()}). to_list(Counter) -> _pipe = erlang:element(2, Counter), maps:to_list(_pipe). -spec most_common(counter(OHY)) -> list({OHY, integer()}). most_common(Counter) -> _pipe = Counter, _pipe@1 = to_list(_pipe), gleam@list:sort( _pipe@1, fun(A, B) -> gleam@int:compare(erlang:element(2, B), erlang:element(2, A)) end ). -spec most_common_n(counter(OIB), integer()) -> list({OIB, integer()}). most_common_n(Counter, N) -> _pipe = Counter, _pipe@1 = most_common(_pipe), gleam@list:take(_pipe@1, N). -spec from_list(list(OJJ)) -> counter(OJJ). from_list(Items) -> update(new(), Items). -spec to_dict(counter(OJM)) -> gleam@dict:dict(OJM, integer()). to_dict(Counter) -> erlang:element(2, Counter). -spec from_dict(gleam@dict:dict(OJQ, integer())) -> counter(OJQ). from_dict(D) -> _pipe = D, {counter, _pipe}.