2012-09-29 19 views
5

Basit bir örnek olarak, L numaralı bir listenin olduğunu varsayalım ve belirli bir sayıdan daha büyük olan ilk öğeyi bulmak istiyorum X. Böyle Liste tanımlama ile yapabilirsiniz:Erlang: Bir listedeki ilk öğe (öğelerin geri kalanını değerlendirmeye almadan)

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

Ama liste çok uzun olabilir ve ilk maçı erkenden olabilir çünkü bu, potansiyel olarak çok verimsiz görünmektedir. Yani merak ediyorum ya a) İlk maçın bulunmasından sonra listedeki elemanların geri kalanını değerlendirmeyecek olan bunu yapmanın etkili bir yolu var mı? veya b) Bu, derlendiğinde, Erlang, karşılaştırmaların geri kalanını her halükarda optimize eder mi?

Bu ben C aradığım şey başarmak şekli şöyledir:

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 */ 
} 

cevap

11

,

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

Güzel. Bu benim çözümümden daha özlü. Aslında 'başarısızlığın' ilk başarısız maçtan sonra değerlendirmeyi durdurduğunu doğrulamak için biraz araştırma yapmak zorunda kaldım. Bu durumu, bir işlevi (mantığı tersine çevirmek zorunda kalmadan) bir işlev olarak belirtebilmenizi sağlayan bir işlevle tamamladım: https://gist.github.com/3807110 – dantswain

3

Buradaile gelip başardı budur. Hala daha iyi bir cevap olup olmadığını ve/veya en basit şeyin en iyi duruma getirilip getirilmediğini (bundan ne kadar çok düşündüğümü, daha fazla şüphe duyduğumu) bilmek isterim.

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

Örnek:

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 

Düzenleme

İşte bir akümülatör olmadan versiyonu. iyi

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

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

yerleşik bir kısayol var sorusunu ele alamazsın ama bu kesinlikle benziyor Kendi yuvarlanmanın doğru yolu ... akümülatörün dışında gereksiz görünüyor. – macintux

+0

Gerçekten iyi bir nokta :) Bu aslında biraz kolaylaştırır. – dantswain

3

gibi bir şey Burada hızlı çözüm:

first_greater([],_) -> undefined; 
first_greater([H|_], Num) when H > Num -> H; 
first_greater([_|T], Num) -> first_greater(T,Num). 
İlgili konular