5

I have a dictionary and want to convert it to a list. Then I would like to sort the resulting list consisting of {Key, Value} pairs from min to max depending on the 2nd element(Value).

Is there a built in sort method for Lists to handle this or how does one do this?

Thanks

some_id
  • 29,466
  • 62
  • 182
  • 304

2 Answers2

13

The function lists:keysort/2 fits like glove for this.

1> lists:keysort(2, [{a,b},{b,a},{b,b}]).

[{b,a},{a,b},{b,b}]

2> lists:keysort(2, [{1,14},{3,10},{2,13}]).

[{3,10},{2,13},{1,14}]

D.Nibon
  • 2,883
  • 1
  • 19
  • 17
  • Awesome. Completely overlooked that. :/ – some_id Dec 06 '10 at 21:29
  • What if I wanted to sort and the only return a list of the First elements? – some_id Dec 06 '10 at 21:32
  • Because the nature of sorting the element sorted on can't be discarded prematureley. Therefor you have to break this up into two steps; Sort and then run: `[ Key || {Key,Value} <- L ]` or the corresponding lists:map/2 function. – D.Nibon Dec 07 '10 at 06:45
  • Upvoting. Your function's the right one for this case. I'm leaving my answer up because it will also finish the sorting on the key if the values are equal. – I GIVE TERRIBLE ADVICE Dec 07 '10 at 16:27
7

The easiest way to sort by the second element would be to define your own sorting function that could work as follows:

fun({KeyA,ValA}, {KeyB,ValB}) -> {ValA,KeyA} =< {ValB,KeyB} end.

And call it in lists:sort/2:

1> lists:sort(fun({KeyA,ValA}, {KeyB,ValB}) -> {ValA,KeyA} =< {ValB,KeyB} end., [{a,b},{b,a},{b,b}]).
[{b,a},{a,b},{b,b}]

This is because Erlang will always automatically compare tuples from first to last element. This function swaps the first and the second element so the second one acts as the first point of comparison. The Key in your dict will then be used to order entries where values are the same.

I GIVE TERRIBLE ADVICE
  • 9,578
  • 2
  • 32
  • 40
  • Nice1. Will this work for key value pairs of [{1, 14}, {3, 10}, {2, 13} ? Integers? Thanks – some_id Dec 06 '10 at 20:13
  • This will work for any value. Erlang terms are always comparable one to another. If your tuple has two values and you want the second one to lead, the function above will cover these cases. You could just try it and see. – I GIVE TERRIBLE ADVICE Dec 06 '10 at 20:37
  • Thanks once again for the help. appreciate it. – some_id Dec 06 '10 at 20:39
  • What if I wanted to sort and the only return a list of the First elements? – some_id Dec 06 '10 at 21:31
  • 1
    `[Key || {Key, _Val} <- List].` – I GIVE TERRIBLE ADVICE Dec 06 '10 at 21:43
  • I did the following: `A = {1, 99}, B = {5, 15}.` `F = fun({key_X, val_X},{key_Y, val_Y}) -> {val_X, key_X} =< {val_Y, key_Y} end.` And then, put it to `lists:sort/2` function. As follows: `lists:sort(F, [A, B]).` But got the error exception : `** exception error: no function clause matching erl_eval:'-inside-an-interpreted-fun-'({1,99},{5,15})` – elgolondrino May 06 '14 at 18:46
  • @IGIVETERRIBLEADVICE Can you explain `[Key || {Key, _Val} <- List].` in more details (e.g. in function)? Thanks beforehand! – elgolondrino May 06 '14 at 18:58
  • 1
    @elgolondrino this basically just returns a list of all the keys. The error you received, however, is due to the fact that you used names like `key_Y`, which are atoms. Variables would require using `KeyY`, where they are case sensitive. Lowercase = atom, Uppercase = variable. – I GIVE TERRIBLE ADVICE May 06 '14 at 21:00