【问题标题】:Erlang lists:index_of/2 function?Erlang 列表:index_of/2 函数?
【发布时间】:2010-11-30 08:34:43
【问题描述】:

我正在寻找一个 Erlang 库函数,它将返回列表中特定元素的索引。

如果

X = [10,30,50,70]
lists:index_of(30, X)

将返回 1 等,就像 java.util.ListindexOf() 方法一样。

Erlang 标准库中是否存在这种方法?我尝试查看列表模块,但没有运气。还是我自己写?

【问题讨论】:

  • 如果你要通过索引访问项目,那么最好看一下数组模块。

标签: list erlang erlang-otp


【解决方案1】:

其他解决方案(注意这些是base-index=1):

index_of(Value, List) ->
   Map = lists:zip(List, lists:seq(1, length(List))),
   case lists:keyfind(Value, 1, Map) of
      {Value, Index} -> Index;
      false -> notfound
   end.

index_of(Value, List) ->
   Map = lists:zip(List, lists:seq(1, length(List))),
   case dict:find(Value, dict:from_list(Map)) of
      {ok, Index} -> Index;
      error -> notfound
   end.

在某些时候,当您传递给这些函数的列表变得足够长时,构建额外列表或字典的开销就会变得过于昂贵。如果您可以通过将列表保持在这些函数之外的格式来避免每次想要搜索列表时都进行构造,那么您可以消除大部分开销。

使用字典将对列表中的值进行哈希处理,并有助于将索引查找时间减少到 O(log N),因此最好将其用于大型单键列表。

一般来说,您(程序员)可以将数据组织成适合您使用方式的结构。我的猜测是,没有内置 index_of 是为了鼓励这种考虑。如果您正在执行单键查找——这就是 index_of() 的真正含义——请使用字典。如果您正在执行多键查找,请使用带有列表的元组列表:keyfind() 等。如果您的列表非常大,最好采用不那么简单的解决方案。

【讨论】:

    【解决方案2】:

    以下函数返回列表中给定元素的索引列表。 Result 可用于获取列表中重复元素第一次或最后一次出现的索引。

    indices_of(Element, L) ->                                                                                                                                                          
        Indices = lists:zip(lists:seq(1,length(L)), L),                                                                                                                                
        [ I || {I, E} <- Indices, E == Element ].   
    

    【讨论】:

      【解决方案3】:

      我认为作者提出了一个有效的案例。这是我来自日志记录应用程序的用例。目的是根据针对不同级别的错误响应要执行的操作来检查错误的严重性。

      get_index(A,L) ->
          get_index(A,L,1).
      get_index(A,[A|_],N) ->
          N;
      get_index(A,[_|T],N) ->
          get_index(A,T,N+1).
      
      get_severity(A) ->
          Severity=[debug,info,warn,error],
          get_index(A,Severity).
      

      【讨论】:

      • 我刚刚写了一个和这个非常相似的方法;我最终使用了类似 get_severity(debug) -> 1;获取严重性(信息)-> 2;等等 - 应该快一点,如果我传递一些无效的东西,透析器会注意到
      • 嘿,我的解决方案与公认的解决方案几乎相同,它遵循 erlang 让它失败的理念。我承认接受的解决方案使用了更好的参数名称(以及没有找到返回)。也许结果应该是 {ok,Index),但我已经有点厌倦了不得不用 OK({ok,X}) -> X 提取我想要的东西,然后当我不放时让透析器抱怨OK({error,X}) -> throw(X)。
      【解决方案4】:

      正如其他人所说,有更有效的方法可以解决这个问题。但是,如果您正在寻找快速的东西,这对我有用:

      string:str(List, [Element]).
      

      【讨论】:

        【解决方案5】:

        这个函数在 Erlang 中非常少见,这可能是它不在标准库中的原因。没有经验丰富的 Erlang 程序员需要它,并且不鼓励使用使用此函数的算法。当有人需要它时,可以为自己的目的而写,但这种非常罕见的情况不是将它包含到stdlib 的理由。以适当的方式设计你的数据结构,而不是要求这个函数。在大多数情况下,需要此功能表明设计存在错误。

        【讨论】:

        • 那么您对 ​​lists:nth 和 lists:nthtail 函数有何看法?
        • 这只是一个荒谬的说法。你完全不知道我需要这个函数做什么。
        • “经验丰富的 Erlang 程序员都不需要它”猜猜你的“经验丰富的 Erlang 程序员”不倾向于处理现实世界的问题?
        • 在这种情况下,您可以执行 Sorted = lists:sort(lists:zip(Randoms, lists:seq(1, length(Randoms)))),然后通过列表获取项目的索引:keyfind(Item, 1, Sorted).
        • 我猜这就是你说的方式。
        【解决方案6】:

        你必须自己定义它,像这样:

        index_of(Item, List) -> index_of(Item, List, 1).
        
        index_of(_, [], _)  -> not_found;
        index_of(Item, [Item|_], Index) -> Index;
        index_of(Item, [_|Tl], Index) -> index_of(Item, Tl, Index+1).
        

        但请注意,访问列表的第 N 个元素是 O(N),因此经常按索引访问列表的算法效率低于按顺序遍历列表的算法。

        【讨论】:

        • 返回像not_found 这样的原子而不是-1 会更像Erlang。这样,如果您忘记测试这种情况,您会很快收到错误。
        • 索引也可以从 1 而不是 0 开始。
        • ... 因为 lists:nth(Index, List) 将 1 视为第一项。
        猜你喜欢
        • 2011-06-15
        • 2015-02-12
        • 2016-08-25
        • 2015-02-01
        • 2017-06-23
        • 2010-12-05
        • 2011-05-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多