Сортировка записей Erlang в списке?
У меня есть запись в erlang:
-record(myrec,
{
id = 0,
price = 0,
quantity = 0
}).
Затем у меня есть список записей, которые я хочу сортировать по id и цене, как по убыванию, так и по возрастанию, где цена является первым ключом, и если две записи имеют одинаковую цену, я хочу отсортировать их по id.
Как я могу определить для этого удовольствие?
Я новичок в Erlang:)
спасибо, nisbus
Ответы
Ответ 1
Это более короткое решение, чем было предложено до сих пор. Сначала определите свою запись:
1> rd(myrec, {id=0, price=0, quantity=0}).
myrec
Затем выдумайте 3 из них:
2> A = #myrec{id=1, price=10, quantity=2}, B = #myrec{id=2, price=4, quantity=3}, C = #myrec{id=3, price=10, quantity=1}.
#myrec{id = 3,price = 10,quantity = 1
Теперь нам нужна функция сравнения. Здесь решение короче. Erlang может сравнивать термины кортежа в том порядке, в котором они появляются, поэтому, если мы хотим сортировать по цене, то по id нам просто нужно сравнить два кортежа формы {PriceA, IdA} < {PriceB, IdB}
:
3> F = fun(X, Y) -> {X#myrec.price, X#myrec.id} < {Y#myrec.price, Y#myrec.id} end.
#Fun<erl_eval.12.113037538>
И подключите его в lists:sort/2
:
4> lists:sort(F, [C,B,A]).
[#myrec{id = 2,price = 4,quantity = 3},
#myrec{id = 1,price = 10,quantity = 2},
#myrec{id = 3,price = 10,quantity = 1}]
Теперь заказ [B, A, C]
и ваш список отсортирован.
Обратите внимание, что если вы хотите отсортировать по нисходящему id, вы можете обмануть его, изменив идентификаторы в кортежах следующим образом:
5> G = fun(X, Y) -> {X#myrec.price, Y#myrec.id} < {Y#myrec.price, X#myrec.id} end.
#Fun<erl_eval.12.113037538>
6> lists:sort(G, [C,B,A]).
[#myrec{id = 2,price = 4,quantity = 3},
#myrec{id = 3,price = 10,quantity = 1},
#myrec{id = 1,price = 10,quantity = 2}]
Предоставление нам [B, C, A]
. Это не очевидно для читателя, поэтому вам лучше документировать его или использовать решение Dustin в этом случае. Преимущество представленного здесь решения состоит в том, что вложенности не требуется. Установив элементы в кортеже в сравнении, вы можете в значительной степени сравнить столько, сколько хотите, не делая код намного дольше.
Ответ 2
Сначала вы выясните, как сравнивать ваши записи:
-spec compare(#myrec{}, #myrec{}) -> boolean().
compare(A, B) ->
case A#myrec.price == B#myrec.price of
true ->
A#myrec.id < B#myrec.id;
_ ->
B#myrec.price < A#myrec.price
end.
Затем вы просто используете обычную функцию lists:sort
со своей функцией сравнения, чтобы получить то, что вы хотите (это тест eunit
выше, который я использовал, чтобы убедиться, что я сделал что-то, что имело смысл):
compare_test() ->
R1 = #myrec{id=5, price=3, quantity=2},
R2 = #myrec{id=6, price=5, quantity=1},
R3 = #myrec{id=7, price=5, quantity=0},
false = compare(R1, R2),
true = compare(R2, R1),
true = compare(R2, R3),
false = compare(R3, R2),
false = compare(R1, R3),
true = compare(R3, R1),
% Run a sort with the above comparator.
[R2, R3, R1] = lists:sort(fun compare/2, [R1, R2, R3]).
Ответ 3
% 3723064
-module(t).
-export([record_sort/0, price_cmp/2, qty_cmp/2]).
-record (item, {id = 0, price = 0, quantity = 0}).
price_cmp(A, B) ->
A#item.price < B#item.price.
qty_cmp(A, B) ->
A#item.quantity < B#item.quantity.
record_sort() ->
Items = [
#item{id=1, price=10, quantity=5},
#item{id=2, price=50, quantity=0},
#item{id=3, price=30, quantity=3},
#item{id=4, price=60, quantity=9}
],
io:format("Unsorted Items: ~p~n", [Items]),
io:format("By Price: ~p~n", [lists:sort({t, price_cmp}, Items)]),
io:format("By Quantity: ~p~n", [lists:sort({t, qty_cmp}, Items)]).
% Alternatively use anonymous functions:
% io:format("By Price: ~p~n", [lists:sort(
% fun(A, B) -> A#item.price < B#item.price end, Items)]),
%
% io:format("By Quantity: ~p~n", [lists:sort(
% fun(A, B) -> A#item.quantity < B#item.quantity end, Items)]).
Это даст (предположим пример файла t.erl
):
1> c(t).
{ok,t}
2> t:record_sort().
Unsorted Items: [{item,1,10,5},{item,2,50,0},{item,3,30,3},{item,4,60,9}]
By Price: [{item,1,10,5},{item,3,30,3},{item,2,50,0},{item,4,60,9}]
By Quantity: [{item,2,50,0},{item,3,30,3},{item,1,10,5},{item,4,60,9}]
ok