2009-07-27 17 views
5

Có cách nhanh chóng để chuyển đổi danh sách phẳng thành danh sách hai bộ sao cho danh sách phẳng như [1,2,3,4,5,6] trở thành [{1,2}, {3,4 không }, {5,6}]?Cách tốt nhất để chuyển đổi một danh sách phẳng thành một bộ hai bộ trong Erlang?

này hoạt động, nhưng nó cảm thấy WRONG chỉ đơn giản:

tuples_from_flat_list(Target) -> 
    TargetWithIndex = lists:zip(lists:seq(1, length(Target)), Target), 
    {K, V} = lists:partition(fun({I, _}) -> I rem 2 == 1 end, TargetWithIndex), 
    lists:zipwith(fun({_, X}, {_, Y}) -> {X, Y} end, K, V). 

Trả lời

2

Phiên bản này là hiệu quả hơn so với phương pháp 'thẳng' với danh sách nối đề xuất trước đó:

combine(L) when length(L) rem 2 == 0 -> combine([], L). 
combine(Acc, []) -> lists:reverse(Acc); 
combine(Acc, [H1,H2|T]) -> combine([{H1, H2}|Acc], T). 

Để chuẩn:

combine.erl

-module(combine). 
-export([reverse/1, straight/1, test/2]). 

test(F, L) -> {Micros, _} = timer:tc(?MODULE, F, [L]), Micros. 

reverse(L) when length(L) rem 2 == 0 -> reverse([], L).         
straight(L) when length(L) rem 2 == 0 -> straight([], L). 

reverse(Acc, []) -> lists:reverse(Acc); 
reverse(Acc, [H1, H2 | T]) -> reverse([{H1, H2} | Acc], T). 

straight(Acc, []) -> Acc; 
straight(Acc, [H1, H2 | T]) -> straight(AcC++ [{H1, H2}], T). 

đầu ra:

130> combine:test(reverse, lists:seq(1,1000)). 
34 
131> combine:test(straight, lists:seq(1,1000)). 
1772 
+0

Có, đảo chiều và tiền tố luôn hiệu quả hơn. Nhưng tôi nghĩ rằng cách tiếp cận "thẳng" hoạt động tốt như Bài 1, theo sau một cách nhanh chóng bởi tiền tố/ngược lại như Bài 2 ...! –

+0

Tại sao bạn đếm chiều dài của danh sách khi bạn không thực hiện một số thông báo lỗi nhạy cảm hơn. Đảo ngược/2 của bạn sẽ tăng thông báo lỗi tương tự như ngược lại/1 của bạn. Đó là công việc vô giá trị và làm chậm nó một chút. –

+1

@Hynek: Tôi nghĩ nó tốt hơn vì nó không hoạt động trước đó. Ngoài ra nó cho biết thêm rõ ràng cho một trong những người sẽ đọc mã số – zakovyrya

3
tuples_from_flat_list(List) -> tuples_from_flat_list(List, []). 

tuples_from_flat_list([], Result) -> lists:reverse(Result). 
tuples_from_flat_list([X, Y|T], Acc) -> tuples_from_flat_list(T, [{X, Y}|Acc]). 

Nó là tốt nhất và cách nhanh nhất.

+0

Trong trường hợp thậm chí không liệt kê và không có bảo vệ, nó không thành công ở cuối quá trình xử lý danh sách, khi tất cả công việc gần như hoàn thành: ** lỗi ngoại lệ: không có điều khoản phù hợp với điều khoản hàm: tuples_from_flat_list ([5], [{3,4}, {1,2}]) – zakovyrya

+0

Có, đó là cố ý. –

10

Cách tiếp cận ngắn nhất và cô đọng nhất:

pair_up([A, B | Tail]) -> 
    [{A,B} | pair_up(Tail)]; 
pair_up([]) -> 
    []. 

Hoặc phiên bản còn mang một accumulator, nhưng vẫn rất thành ngữ Erlang:

pair_up(List) -> 
    pair_up(List, []). 

pair_up([A, B | Tail], Acc) -> 
    pair_up(Tail, [{A,B} | Acc]); 
pair_up([], Acc) -> 
    lists:reverse(Acc). 

Xem phần này trong hướng dẫn hiệu quả erlang "Myth: Tail-recursive functions are MUCH faster than recursive functions".

Như bạn sẽ thấy, cả hai cách tiếp cận sẽ dẫn đến lối thoát 'badarg' khi được gọi với danh sách độ dài không đồng đều. Điều này có lẽ là mong muốn từ một viễn cảnh không nhanh.

Cũng đọc "Myth: '++' is always bad" để xem lý do tại sao chúng tôi tạo bộ tích lũy ngược lại chỉ để đảo ngược khi thực hiện, thay vì thêm vào cuối danh sách.

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