【问题标题】:How to do logical tests for all list elements in mathematica如何对mathematica中的所有列表元素进行逻辑测试
【发布时间】:2012-01-20 17:02:44
【问题描述】:

我有一个列表,我想对每个元素进行逻辑测试,如果其中任何一个不满足这个条件,则返回 false。我想在 Mathematica 中写这个或找到一个内置函数,但似乎 ForAll 实际上并没有这样做。

我的问题是:如何最有效地做到这一点?

奖励:Exists 函数类似:即如果列表中有任何元素满足条件,则返回 true。

【问题讨论】:

  • 您会寻找 And 和/或 Or 吗? (我喜欢听起来的方式。但它可能看起来更好 (&&)^2 (||)^2 ) ForAll 和 Exists 确实不适合这个,尽管它们可以适应。示例:解决[ForAll[x, x == 1 || x == 2 || x == 3, x > 2.5]] 将返回 False。
  • 这个问题之前在这里被问过,实际上不止一次。见这里:stackoverflow.com/questions/4181470/…,这里:stackoverflow.com/questions/4911827/…

标签: wolfram-mathematica


【解决方案1】:

此答案并非旨在展示最有效的方法,而是一种替代方法,用于展示 Mathematica 中一些重要核心功能的教学目的。 p>

nixeagle 的回答避免显式测试列表中的每个元素。如果测试不适合包含在 Select 的第三个参数中,那么下面的内容可能有用。

为此,您需要了解标准的OrAnd 函数,以及Map (/@)Apply (@@) 命令,这对于任何Mathematica 用户来说都非常重要。 (见this tutorial

这是一个简单的例子。

In[2]:= data = RandomInteger[{0, 10}, {10}]

Out[2]= {10, 1, 0, 10, 1, 5, 2, 2, 4, 1}

In[4]:= # > 5 & /@ data

Out[4]= {True, False, False, True, False, False, False, False, False, \
False}

In[6]:= And @@ (# > 5 & /@ data)

Out[6]= False

这里发生的情况是,您正在使用Map 将函数(“大于 5”)映射到列表的每个元素,以获取 True/False 值列表。然后,您将标准逻辑函数 And 应用于整个列表以获取单个布尔值。

这些都是 Mathematica 中的核心功能,我建议您仔细阅读这些函数的文档并练习使用它们。

这不是最有效的方法,但对于小问题你不会注意到差异。

In[11]:= Do[Select[data, ! # > 5 &, 1] === {}, {10000}] // Timing

Out[11]= {0.031, Null}

In[12]:= Do[And @@ (# > 5 & /@ data);, {10000}] // Timing

Out[12]= {0.11, Null}

对于ExistsSelect 的替代方案将是MatchQ 用于模式或MemberQ 用于显式值。该文档有一些有用的示例。

【讨论】:

  • 这不好。 所有元素都会被测试,即使第一个失败了。
  • @Mr.Wizard 这个问题已经在这个问题的先前版本中得到了完整的解决(这是重复的。可惜我现在才看到) - 这里:stackoverflow.com/questions/4181470/…,这里: stackoverflow.com/questions/4911827/…
  • @Mr.Wizard 也许,为时已晚(或者可能不是)。只是很遗憾你提到的方面没有得到足够的强调(虽然acl'a和Hideric Browne的解决方案考虑到了这一点,但是acl's更专门用于数字lsists,而Hideric's有点粗心,有例外)。跨度>
  • @Mr.Wizard 我的观点是,考虑到问题的内容,让 OP 了解一些 Mathematica 基础知识比担心效率要好。
  • @Mr.Wizard 我忘记了。我将修改我的答案,以明确表明我并不是要展示最有效的方法。
【解决方案2】:

您问题第一部分的答案可能是这样的:

forAll[list_, cond_] := Select[list, ! cond@# &, 1] === {};

这样使用:

forAll[{1, 2, 3, 3.5}, IntegerQ]

“exists”函数已经原生实现为MemberQ。它可以重新实现为:

exists[list_,cond_] := Select[list, cond, 1] =!= {};

像这样使用它

exists[Range@100, (10 == # &)]

返回 true 为 10 的元素导致 Select 返回不等于 {}{10}

【讨论】:

  • 该死的。当我意识到这与您发布的完全相同时,我正要发布答案。
  • 这是一个非常快的接受,也许你应该取消选中我的答案,看看其他人是否能做得更好:)。另外,我只真正回答了您问题的第二部分,尽管通过一些(正确的)调整,您也可以回答问题的第一部分。
  • 是的,这就是为什么我在意识到它没有正确回答问题后将其删除的原因。并且在收集完整的元素列表后使用Length 根本不是很有效。
  • 对于 Mathematica, IIRC 中的列表,长度应为 O(1)。但是,它在使用内存方面效率低下,因为您正在创建列表然后获取它的长度。 Mathematica 中的大多数函数式解决方案似乎都存在内存问题。
  • @MikeBantegui 对,我已经编辑了这个以减少内存浪费:)
【解决方案3】:

nixeagle 获得了奖励部分,但我会按照以下方式完成第一部分:

AllSatisfy[expr_, cond_] := Length@Select[expr, cond] == Length@expr

【讨论】:

    【解决方案4】:

    不要太认真,但是这个

    ClearAll[existsC];
    existsC[cond_] := With[
      {c = cond},
      Compile[
       {{l, _Integer, 1}},
       Module[
        {flag = False, len = Length@l},
        Do[
         If[cond[l[[i]]],
           flag = True; Break[];
           ];,
         {i, 1, len}];
        flag
        ],
       CompilationTarget -> "C"
       ]
      ]
    

    在我的机器上似乎比 nixeagle's 解决方案快 300 倍左右。它的作用是发出一个编译函数,该函数接受一个列表并将其元素与给定条件(在编译时固定)进行比较,如果其中任何一个匹配,则返回 True

    使用方式如下:用相应的cond编译,例如

    t = existsC[# == 99999 &];
    

    然后

    t[Range@100000] // timeIt
    

    返回2.33376*10^-6(最坏的情况,因为我只是线性搜索并且匹配元素位于末尾)而

    exists[Range@100000, (99999 == # &)] // timeIt
    

    返回0.000237162(这里,timeItthis)。

    【讨论】:

    • +1 展示了一种非常酷的方式来利用 Compile 并让我想到 Common Lisp 中的 (defmacro ...)!这可能是我第一次有趣遇到一些人称之为Mathematica“元”编程的东西。是的,我很想知道为什么"WVM" 更快。最后不要削弱这个答案的纯 awesomeness ......但我强烈怀疑这仅对数字有效,而不是符号或其他任何 Compile 将无法使用(尽管我希望它确实处理了更多的东西!)。
    • @nixeagle 谢谢!你是对的,它不适用于Compile 不支持的对象列表,或者不均匀的列表等。
    • +1。你不需要外部的With - 规则(参数传递)具有(几乎)相同的语义,也可以用来注入东西。至于时间,在我的机器上,C 编译的代码比 WVM 编译的快得多(正如我们所期望的那样),这与您的观察相矛盾。
    • 顺便说一下,这是您的代码的较短版本:existsC[cond_] := Compile[{{l, _Integer, 1}}, Do[If[cond[el], Return[True]], {el, l}] == True, CompilationTarget -> "C"]。它也可能会快一点。
    • @Leonid 谢谢。使用Null==True 来返回False 很聪明,即使它迫使我在阅读代码时不得不思考。
    【解决方案5】:

    即使&&|| 执行短路评估,即不要不必要地评估他们的论点,我怀疑基于Select[]Map[] 的解决方案不会从中受益太多。这是因为他们将逻辑测试应用于每个元素,在执行它们之间的连接/分离之前构建一个布尔真值列表。如果您指定的测试速度很慢,这可能是一个真正的瓶颈。

    所以这里有一个变体,它也对条件进行短路评估:

    allSatisfy[list_, cond_] :=
       Catch[Fold[If[cond[#2], True, Throw[False]] &, True, list]]
    

    测试列表中的任何元素是否满足条件是否对称:

    anySatisfy[list_, cond_] := 
       Catch[Fold[If[cond[#2], Throw[True], False] &, False, list]]
    

    当然,这同样可以使用诸如While[] 之类的过程循环来完成(坦率地说,更容易),但我对函数式编程情有独钟!

    【讨论】:

    • 我会使用更安全的标记异常。对于使用它但与您的建议类似的实现,请在此处查看我的答案的第二部分:stackoverflow.com/questions/4911827/…
    • Select 的第三个参数允许它在第一次匹配后“短路”测试。
    【解决方案6】:

    基于模式的方法:

    forAll[list_, test_] := MatchQ[ list, _[__?test] ]
    

    MemberQ 已经实现存在。


    Mathematica 10 为此提供了一个新函数:AllTrue。当所有元素都通过测试时,我的函数似乎要快一点:

    a = Range[2, 1*^7, 2];
    
    AllTrue[a, EvenQ] // Timing // First
    forAll[a, EvenQ]  // Timing // First
    
    1.014007
    
    0.936006
    

    但是,如果提前退出,新功能的好处就会变得明显:

    a[[123456]] = 1;
    
    AllTrue[a, EvenQ] // Timing // First
    forAll[a, EvenQ]  // Timing // First
    
    0.031200
    
    0.265202
    

    【讨论】:

      【解决方案7】:

      有一个简单的解决方案:

      In[1401]:= a = {1, 2, 3}
      
      Out[1401]= {1, 2, 3}
      
      In[1398]:= Boole[Thread[a[[2]] == a]]
      
      Out[1398]= {0, 1, 0}
      
      In[1400]:= Boole[Thread[a[[2]] >= a]]
      
      Out[1400]= {1, 1, 0}
      
      In[1402]:= Boole[Thread[a[[2]] != a]]
      
      Out[1402]= {1, 0, 1}
      

      成功了!

      【讨论】:

        猜你喜欢
        • 2015-06-22
        • 1970-01-01
        • 1970-01-01
        • 2017-12-27
        • 1970-01-01
        • 2014-06-27
        • 1970-01-01
        • 1970-01-01
        • 2021-12-08
        相关资源
        最近更新 更多