【问题标题】:Erlang: First element in a list matching some condition (without evaluating the rest of the elements)Erlang:列表中匹配某个条件的第一个元素(不评估其余元素)
【发布时间】:2012-09-21 08:28:58
【问题描述】:

举个简单的例子,假设我有一个数字列表L,我想找到大于某个特定数字X 的第一个元素。我可以用这样的列表推导来做到这一点:

(mynode@127.0.0.1)24> L = [1, 2, 3, 4, 5, 6].              
[1,2,3,4,5,6]
(mynode@127.0.0.1)25> X = 2.5.
2.5
(mynode@127.0.0.1)26> [First | _] = [E || E <- L, E > X].  
[3,4,5,6]
(mynode@127.0.0.1)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 */
}

【问题讨论】:

    标签: list erlang list-comprehension


    【解决方案1】:

    这就是 能够想出的。我仍然想知道是否有更好的答案和/或是否对最简单的事情进行了优化(我想的越多,我就越怀疑)。

    -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】:

    嗯,有点像

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

    【讨论】:

    • 不错。这比我的解决方案更简洁。我确实需要做一些事情来验证dropwhile 确实在第一次失败匹配后停止评估。我将它封装在一个函数中,让您可以将条件指定为函数(无需反转逻辑):gist.github.com/3807110
    【解决方案3】:

    这里有一个快速的解决方案:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-20
      • 2015-07-13
      • 1970-01-01
      • 1970-01-01
      • 2016-11-25
      • 2014-05-21
      • 2019-01-06
      相关资源
      最近更新 更多