对列表中的 Erlang 记录进行排序?

发布于 2024-09-19 01:38:47 字数 273 浏览 4 评论 0原文

我在 erlang 中有一条记录:

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

然后我有一个记录列表,我想按 id 和价格排序,按降序和升序排列,其中价格是第一个键,如果两个记录具有相同的价格,我想对它们进行排序通过 ID。

我如何为此定义乐趣?

我是 Erlang 的新手:)

谢谢, 尼斯总线

I have a record in erlang:

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

I then have a list of records that I want to sort by id and price, both in descending and ascending order, where price is the first key and if two records have the same price I want to sort those by id.

How can I define a fun for this?

I'm a newb at Erlang :)

thanks,
nisbus

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

悸初 2024-09-26 01:38:50
% 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
% 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)]).

This will yield (assuming example file 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
等往事风中吹 2024-09-26 01:38:49

这是比迄今为止建议的解决方案更短的解决方案。首先定义您的记录:

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} {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 降序排序,您可以通过反转元组中的 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]。这对读者来说并不明显,因此您最好将其记录下来或在这种情况下使用达斯汀的解决方案。这里提出的解决方案的优点是不需要嵌套。通过在比较中的任一元组中设置元素,您几乎可以根据需要比较任意数量的元素,而无需使代码变得更长。

This is a shorter solution than what has been suggested so far. First define your record:

1> rd(myrec, {id=0, price=0, quantity=0}).
myrec

Then let's invent 3 of them:

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

Now we need a comparison function. This is where the solution is shorter. Erlang can compare terms of a tuple in the order they appear, so if we want to sort by price, then by id, we just have to compare two tuples of the form {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>

And plug it in 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}]

The order is now [B, A, C] and your list is sorted.

Note that if you wanted to sort by descending id instead, You could trick it by reversing the ids in the tuples as follows:

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}]

Giving us [B, C, A]. This is not obvious to the reader, so you'd better document it or use Dustin's solution in this case. The advantage of the solution presented here is that there is no nesting required. By setting elements in either tuple in the comparison, you can pretty much compare as many of them as you want without making the code that much longer.

大姐,你呐 2024-09-26 01:38:49

首先,您弄清楚如何比较您的记录:

-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]).

First, you figure out how to compare your records:

-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.

Then, you just use the normal lists:sort function with your comparison function to get what you want (this is an eunit test of the above I ran to make sure I did something that made sense):

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]).
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文