【问题标题】:erlang list filter questionerlang列表过滤问题
【发布时间】:2011-02-24 17:28:13
【问题描述】:

我有清单 - Sep1:

[
   ....
   ["Message-ID", "AAAAAAAAAAAAAAAAAAA"],
   ["To", "BBBBBBBBBBBBBBBBB"]
   ...
]

例如,我尝试获取第一项 = Message_ID 的元素:

lists:filter(fun(Y) -> (lists:nth(1,lists:nth(1,Y)) =:= "Message-ID") end, Sep1).

但我得到错误:

 exception error: no function clause matching lists:nth(1,[])

 in function  utils:'-parse_to/1-fun-1-'/1

 in call from lists:'-filter/2-lc$^0/1-0-'/2

但如果我:

io:format(lists:nth(1,lists:nth(1,Sep1))).
> Message-ID

怎么了?

谢谢。

【问题讨论】:

  • lists:filter 调用列表中每个元素的乐趣。您下面的代码只是将整个列表传递给lists:nth
  • Theb 如何按每个列表的第一个元素过滤我的列表?
  • 我怀疑您在某个地方还有其他问题。当我将您的Sep1 和您的lists:filter 调用复制到我的Erlang shell 中时,我得到[] - 当然不是正确的答案,但与您得到的错误不同。您确定您的Sep1 粘贴正确吗?

标签: list filter erlang


【解决方案1】:

最好将表示更改为[{Key, Value}, ...],这样您就可以使用lists:key* 函数、proplists 模块,或者将其转换为dictdict:from_list/1

但如果您仍想使用lists:filter/2,您可以按以下第一个元素过滤列表列表:

lists:filter(fun ([K | _]) -> K =:= "Message-ID" end, ListOfLists).

如果您想提取第一个元素与“Message-ID”匹配的列表的尾部,您可以使用list comprehensions

[Tail || ["Message-ID" | Tail] <- ListOfLists].

【讨论】:

  • 如果初始列表的一个元素是空列表,则此操作失败。
  • lists:key* 函数和 lists:filter 示例按预期工作,对应 3 个元素元组和 3 个元素列表
  • fun ([K | _]) -&gt; K =:= ExpectedValue; (_) -&gt; false end 适用于任何类型的元素。但是你不应该先检查你的输入数据吗?
  • 另外,您可以直接进行模式匹配,即fun (["Message-ID" | _]) -&gt; true; (_) -&gt; false end
  • 是的,如果使用第二个子句(如上面的评论),但它不适用于原始示例。实际上我不喜欢 cmets 中的示例,因为任何东西都可以匹配,但您必须知道您的数据。
【解决方案2】:

为什么要使用两个嵌套的lists:nth 调用?

lists:filter(fun(Y) -&gt; lists:nth(1, Y) =:= "Message-ID" end, Sep1) 为我工作并返回一个包含您想要的元素的列表(第一个元素为"Message-ID" 的列表)。只需对该列表进行模式匹配即可获得您想要的元素,例如如果你只想要一个这样的元素,你可以这样做:

case lists:filter(fun(Y) -> lists:nth(1, Y) =:= "Message-ID" end, Sep1) of
  [Result] -> % do something with it;
  [] -> % no such element found
end

【讨论】:

  • 投反对票:当您投反对票时,请留下评论,解释您认为哪些错误和/或误导...
【解决方案3】:

你可能想要的是这个:

[B || [A,B|_] <- L, A =:= "Message-ID"].

这不假定嵌套列表的任何长度:

它将返回所有第一个元素为“Message-ID”的内部列表的第二个元素的列表

如果您确定只有一个“Message-ID”并且想要抛出错误,否则:

[X] = [B || [A,B|_] <- L, A =:= "Message-ID"].

如果你只想要第一个(没有时仍然抛出错误):

[X|_] = [B || [A,B|_] <- L, A =:= "Message-ID"].

要了解这段代码的作用,我建议阅读 official Erlang documentation 关于列表推导和关于同一主题的 Learn You Some Erlang 章节:List Comprehensions

【讨论】:

    【解决方案4】:

    假设您的列表仅包含元素,每个元素都有 2 个元素,您可以使用列表推导来执行以下操作:

    1> L = [["Message-ID","AAAAAAAA"],["To","BBBBBBBBBBB"]].
    [["Message-ID","AAAAAAAA"],["To","BBBBBBBBBBB"]]
    2> [[A,B]||[A,B] <- L, A =:= "Message-ID"].
    [["Message-ID","AAAAAAAA"]]
    

    希望这会有所帮助。

    【讨论】:

    • 不,列表中没有 2 个元素。
    • 他的代码只假设内幕列表有2个元素
    • -1:假设内部列表包含两个元素,在这种情况下,首先没有理由使用列表。
    • 并且请在比较中使用=:=,使用==无缘无故是不好的例子。
    • 感谢您提及这一点。我错过了这一点,因为我通常使用 '=:=' 并且完全同意在 erlang 中使用 "==" 是一种不好的做法。
    【解决方案5】:

    您可以创建自己的过滤器(不关心元素的数量):

        filter(List) -> filter(List,[]).
    
        filter([],Acc) -> lists:reverse(Acc);
        filter([[]|Tail],Acc) -> filter(Tail,Acc);
        filter([[H|T]|Tail],Acc) ->
          case H =:= "Message-ID" of
            true -> filter(Tail,[[H|T]|Acc]);
            _ -> filter(Tail,Acc)
          end.
    

    【讨论】:

    • 我可能会在已经内置的:my_filter(F, L) -&gt; lists:filter(fun(["Message-ID"|T]) -&gt; F(T); (_) -&gt; false end, L). 或类似的东西上定义它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 2020-02-20
    • 1970-01-01
    相关资源
    最近更新 更多