2010-09-16 38 views
10

Tôi có một kỷ lục trong erlang:Sắp xếp các bản ghi Erlang trong một danh sách?

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

sau đó tôi có một danh sách các hồ sơ mà tôi muốn sắp xếp theo id và giá cả, cả về giảm dần và thứ tự tăng dần, nơi giá là chìa khóa đầu tiên và nếu hai kỷ lục có cùng một mức giá tôi muốn sắp xếp chúng theo id.

Tôi làm cách nào để xác định điều thú vị cho điều này?

tôi là một newb tại Erlang :)

cảm ơn, nisbus

Trả lời

14

Đây là một giải pháp ngắn hơn so với những gì đã được đề xuất cho đến nay. Đầu tiên xác định hồ sơ của bạn:

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

Sau đó, chúng ta hãy phát minh ra 3 trong số họ:

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 

Bây giờ chúng ta cần một hàm so sánh. Đây là nơi giải pháp ngắn hơn. Erlang có thể so sánh về một tuple theo thứ tự chúng xuất hiện, vì vậy nếu chúng ta muốn sắp xếp theo giá, sau đó bởi id, chúng tôi chỉ phải so sánh hai bộ dữ liệu của 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> 

Và cắm nó trong 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}] 

Đơn đặt hàng bây giờ là [B, A, C] và danh sách của bạn được sắp xếp.

Lưu ý rằng nếu bạn muốn sắp xếp theo giảm dần id thay vào đó, Bạn có thể đánh lừa nó bằng cách đảo ngược các id trong các bộ như sau:

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

Cho chúng tôi [B, C, A]. Điều này là không rõ ràng cho người đọc, vì vậy bạn nên tài liệu tốt hơn hoặc sử dụng giải pháp của Dustin trong trường hợp này. Ưu điểm của giải pháp được trình bày ở đây là không có yêu cầu làm tổ. Bằng cách thiết lập các phần tử trong tuple trong so sánh, bạn có thể so sánh khá nhiều phần tử như bạn muốn mà không cần tạo mã dài hơn nhiều.

+0

Thats chỉ đơn giản là mát mẻ. Cảm ơn – nisbus

+0

Đó là trường hợp sau đó tại sao thậm chí xác định một hàm f, tại sao không chỉ danh sách: sắp xếp ([C, B, A])? – Vishal

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

này sẽ mang lại (giả dụ tập tin 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 
2

Trước tiên, bạn tìm ra cách so sánh hồ sơ của bạn:

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

Sau đó, bạn chỉ cần sử dụng bình thường lists:sort chức năng với chức năng so sánh của bạn để có được những gì bạn muốn (đây là một thử nghiệm eunit những điều trên tôi chạy đến chắc chắn rằng tôi đã làm một điều gì đó có ý nghĩa):

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

Xin cảm ơn, đây là mẹo. – nisbus

Các vấn đề liên quan