2012-09-29 36 views
5

Ví dụ đơn giản, giả sử tôi có danh sách các số L và tôi muốn tìm phần tử đầu tiên lớn hơn một số số cụ thể X. Tôi có thể thực hiện việc này với tính năng hiểu danh sách như sau:Erlang: Phần tử đầu tiên trong danh sách khớp với một số điều kiện (không đánh giá phần còn lại của các phần tử)

([email protected])24> L = [1, 2, 3, 4, 5, 6].    
[1,2,3,4,5,6] 
([email protected])25> X = 2.5. 
2.5 
([email protected])26> [First | _] = [E || E <- L, E > X]. 
[3,4,5,6] 
([email protected])27> First. 
3 

Nhưng điều này có vẻ rất không hiệu quả vì danh sách có thể rất dài và khớp đầu tiên có thể sớm. Vì vậy, tôi tự hỏi liệu một trong hai) Có một cách hiệu quả để làm điều này mà sẽ không đánh giá phần còn lại của các yếu tố trong danh sách sau khi trận đấu đầu tiên được tìm thấy? hoặc b) Khi điều này được biên dịch, Erlang có tối ưu hóa phần còn lại của các so sánh không?

Đây là cách tôi sẽ đạt được những gì tôi đang tìm kiếm trong C:

int first_match(int* list, int length_of_list, float x){ 
    unsigned int i; 
    for(i = 0; i < length_of_list, i++){ 
     if(x > list[i]){ return list[i]; } /* immediate return */ 
    } 
    return 0.0; /* default value */ 
} 

Trả lời

11

tốt, cái gì đó như

firstmatch(YourList, Number) -> 
    case lists:dropwhile(fun(X) -> X =< Number end, YourList) of 
    [] -> no_solution; 
    [X | _] -> X 
    end. 
+1

Tuyệt. Điều này là ngắn gọn hơn so với giải pháp của tôi. Tôi đã phải làm một chút tìm kiếm để xác minh rằng 'dropwhile' trong thực tế dừng đánh giá sau khi trận đấu thất bại đầu tiên. Tôi bọc nó lên trong một hàm cho phép bạn chỉ định điều kiện như một hàm (mà không phải đảo ngược logic): https://gist.github.com/3807110 – dantswain

3

Đây là những gì tôi đã có thể đưa ra. Tôi vẫn muốn biết nếu có một câu trả lời tốt hơn và/hoặc nếu điều đơn giản nhất được tối ưu hóa (càng có nhiều tôi nghĩ về nó, tôi càng nghi ngờ nó).

-module(lazy_first). 

-export([first/3]). 

first(L, Condition, Default) -> 
    first(L, [], Condition, Default). 

first([E | Rest], Acc, Condition, Default) -> 
    case Condition(E) of 
    true -> E; 
    false -> first(Rest, [E | Acc], Condition, Default) 
    end; 

first([], _Acc, _Cond, Default) -> Default. 

Ví dụ:

14> lazy_first:first([1, 2, 3, 4, 5], fun(E) -> E > 2.5 end, 0.0). 
3 
15> lazy_first:first([1, 2, 3, 4, 5], fun(E) -> E > 5.5 end, 0.0). 
0.0 

Sửa

Dưới đây là một phiên bản mà không có một ắc.

first([E | Rest], Condition, Default) -> 
    case Condition(E) of 
    true -> E; 
    false -> first(Rest, Condition, Default) 
    end; 

first([], _Cond, Default) -> Default. 
+2

Không thể giải quyết các câu hỏi liệu có một built-in phím tắt, nhưng điều này chắc chắn trông giống như cách thích hợp để cuộn của riêng bạn ... ngoại trừ tích lũy của bạn có vẻ không cần thiết. – macintux

+0

Điểm thực sự tốt :) Điều đó thực sự đơn giản hóa nó một chút. – dantswain

3

Dưới đây là một giải pháp nhanh chóng:

first_greater([],_) -> undefined; 
first_greater([H|_], Num) when H > Num -> H; 
first_greater([_|T], Num) -> first_greater(T,Num). 
Các vấn đề liên quan