Сортировка записей Erlang в списке? - PullRequest
10 голосов
/ 16 сентября 2010

У меня есть запись в эрланге:

-record(myrec,
    { 
      id = 0,
      price = 0,
      quantity = 0
    }).

Затем у меня есть список записей, которые я хочу отсортировать по идентификатору и цене, как в порядке убывания, так и в порядке возрастания, где цена - это первый ключ, аесли две записи имеют одинаковую цену, я хочу отсортировать их по id.

Как я могу определить забаву для этого?

Я новичок в Erlang:)

спасибо, nisbus

Ответы [ 3 ]

14 голосов
/ 16 сентября 2010

Это более короткое решение, чем было предложено до сих пор.Сначала определите вашу запись:

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

Теперь нам нужна функция сравнения.Вот где решение короче.Эрланг может сравнивать термины кортежа в порядке их появления, поэтому, если мы хотим отсортировать по цене, то по 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], и ваш список отсортирован.

Обратите внимание, что если вы хотите отсортировать по по убыванию Вместо этого, вы можете обмануть его, изменив идентификаторы в кортежах следующим образом:

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].Это не очевидно для читателя, поэтому вам лучше документировать это или использовать решение Дастина в этом случае.Преимущество решения, представленного здесь, заключается в том, что нет необходимости в вложении.Установив элементы в любом кортеже для сравнения, вы можете в значительной степени сравнить их столько, сколько захотите, не делая код намного длиннее.

2 голосов
/ 16 сентября 2010

Сначала вы выясните, как сравнивать свои записи:

-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]).
0 голосов
/ 16 сентября 2010
% 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...