【问题标题】:Sorting Erlang records in a list?对列表中的 Erlang 记录进行排序?
【发布时间】:2010-09-16 21:51:51
【问题描述】:

我有一个erlang记录:

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

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

我该如何定义这个乐趣?

我是 Erlang 的新手 :)

谢谢, 尼斯巴士

【问题讨论】:

    标签: sorting erlang


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

    【讨论】:

    • 既然如此,那为什么还要定义一个函数f,为什么不只是lists:sort([C,B,A])?
    【解决方案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
      

      【讨论】:

        猜你喜欢
        • 2013-04-28
        • 2013-07-17
        • 1970-01-01
        • 1970-01-01
        • 2022-01-06
        • 2018-06-21
        • 2019-08-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多