2012-09-29 24 views
5

作爲一個簡單示例,假設我有一個數字列表L,並且我想查找大於某個特定數字的第一個元素X。我可以列表理解這樣做:Erlang:匹配某些條件的列表中的第一個元素(不計算其餘元素)

([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 

但這似乎可能是非常低效的,因爲這個名單可以很長,第一場比賽可能是早期。所以我想知道是否a)是否有一種有效的方法來做到這一點,在找到第一個匹配之後不會評估列表中的其餘元素?或者b)當它被編譯時,Erlang是否會優化剩餘的比較呢?

這是我將如何實現我期待在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 */ 
} 

回答

11

很好,像

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

不錯。這比我的解決方案更簡潔。我確實需要做一些小小的觀察,以確認在第一次失敗比賽之後,「落差」確實會停止評估。我把它封裝在一個函數中,可以讓你指定條件作爲一個函數(而不必顛倒邏輯):https://gist.github.com/3807110 – dantswain

3

這裏是能拿出。我仍然想知道是否有更好的答案和/或最簡單的事情是否得到了優化(我越想越多,我越懷疑它)。

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

實施例:

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 

編輯

這裏沒有儲液器的版本。

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

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

無法解決是否有一個內置的快捷方式的問題,但是這肯定看起來像適當的方式來推出自己的...除了你的累加器似乎沒有必要。 – macintux

+0

真的好點:)這實際上簡化了一下。 – dantswain

3

這裏有一個快速的解決方案:

first_greater([],_) -> undefined; 
first_greater([H|_], Num) when H > Num -> H; 
first_greater([_|T], Num) -> first_greater(T,Num). 
相關問題