tags:

views:

79

answers:

2

How does one sort a list in Erlang depending on a tag for each element?

If I have a process which loops and receives a single value from multiple processes and then I want to arrange the list according to the tag(which is an index) as an element is received.

How does one do this without using BIFs?

I currently do the following but would like to arrange the list when an element is added, like an insertion sort using the tags.

fibLoop(calcData) ->
receive
 {Number, Tag} ->
 fibLoop([{Number, Tag}|calcData]);
+2  A: 

Something like this would probably work:

insert({_, Tag} = Data, [{_,HTag}|_] = List) when Tag >= HTag ->
  [Data | List];
insert(Data, [H | T]) ->
  [H | insert(Data, T)];
insert(Data, []) ->
  [Data].
Lukas
Thanks. What if I only want the numbers as output, so once sorted, remove the tag(second tuple element) and return a list of the numbers?
alJaree
you could use `lists:map()`
ZeissS
A simple way to remove the tags is to use a list comprehension, e.g. [K || {K,V} <- [{1,a}, {2,b}]] -> [1,2].
bjnortier
The above code will result in a list which is reversed (i.e. highest tag first), so it should be Tag < HTag
bjnortier
@Lukas - Thanks. Does this work for entering an element one by one? I have multiple processes and will be receiving computations from each so they wont be received by my master process in the correct order. Is it better to add the element to a sorted list as each item is received? Or is it better to receive all items and then pass the entire list to a sorting method and then drop the tags, which will result in a list of the answered computations in the correct order.
alJaree
It depends on what your requirements are. If you want it to use as litlle CPU as possible then you probably want to do the sorting using lists:keysort(2, List) after you have received all info. If you want to deliver the sorted list as fast as possible when the last message is received (and there is CPU time available to do some preemptive sorting) then this type of insertion sort might be faster. Usually though the lists functions are really fast and it is hard to beat them in pure performance and it adds another level of complexity to your code. Early optimizations are the root of all evil.
Lukas
+2  A: 

There are multiple ways to do what you want, a bit depending on what you want to use the value for later.

Easy solution would be to use gb_trees. gb_trees are a sorted structure that you can loop over using an iterator.

Or if you want to keep it simple and have a list you could use orddict (or possibly ordsets).

orddict:store(Number, Tag, CalcData)

to insert {Number, Tag} into an ordered list. See documentation for orddict for more information.

To get the smallest value in the list you can use hd/1, and to get the biggest lists:last/1 (not that I recommend lists:last, mind you).

Daniel Luna