Philip
Philip

Reputation: 1532

Find list element having smallest mapped value?

Does Erlang have the equivalent of Ruby's min_by?

Suppose I have a list:

[
  [{right, 1}, {up, 5}, {left, 4}], %element 1
  [{up, 2}, {right, 3}, {down, 1}], %element 2
  ... % element N
]

And a function that maps each of these elements to a scalar, such as:

f([{right, 1}, {up, 5}, {left, 4}]) -> 78.
f([{up, 2}, {right, 3}, {down, 1}]) -> 6.

Now I want to find the element that maps to the smallest value. In this example, I want to find [{up, 2}, {right, 3}, {down, 1}].

How can Erlang's standard library help me with this?

Upvotes: 1

Views: 70

Answers (2)

Hynek -Pichi- Vychodil
Hynek -Pichi- Vychodil

Reputation: 26121

You can use fact that all Erlang terms are comparable and tuple has dictionary order.

MinBy = fun(L, F) ->
        {_, Min} = lists:min([{F(X), X} || X <- L]),
        Min
    end.
L = [
    [{right, 1}, {up, 5}, {left, 4}] %element 1
  , [{up, 2}, {right, 3}, {down, 1}] %element 2
].
F = fun([{right, 1}, {up, 5}, {left, 4}]) -> 78;
       ([{up, 2}, {right, 3}, {down, 1}]) -> 6
    end.
MinBy(L, F).

Upvotes: 0

Dogbert
Dogbert

Reputation: 222198

There isn't a builtin function to do exactly this, but you can write a simple tail recursive function for this that would be as efficient as possible in pure Erlang:

min_by([H|T], F) ->
  min_by(T, F, H, F(H)).

min_by([H|T], F, MinValue, MinMapped) ->
  case F(H) of
    NewMapped when NewMapped < MinMapped ->
      min_by(T, F, H, NewMapped);
    _ ->
      min_by(T, F, MinValue, MinMapped)
  end;
min_by([], _, MinValue, _) -> MinValue.
1> c(a).
{ok,a}
2> a:min_by([1, 2, 3], fun (2) -> 0; (_) -> 1 end).
2

Upvotes: 1

Related Questions