如何对mathematica中的所有列表元素进行逻辑测试

时间:2011-12-14 22:31:49

标签: wolfram-mathematica

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

我的问题是:如何最有效地完成这项工作?

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

7 个答案:

答案 0 :(得分:9)

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

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

使用如下:

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

“存在”功能已在本机实现为MemberQ。它可以重新实现为:

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

一样使用它
exists[Range@100, (10 == # &)]

返回true,因为10是导致Select返回{10}且不等于{}的元素。

答案 1 :(得分:8)

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

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用于显式值。该文档有一些有用的例子。

答案 2 :(得分: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)。

答案 3 :(得分:4)

基于模式的方法:

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

答案 4 :(得分:1)

即使&&||执行短路评估,即不要不必要地评估他们的论点,我怀疑基于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[]这样的程序循环同样可以(坦率地说,更容易),但我对函数式编程情有独钟!

答案 5 :(得分:0)

nixeagle得到了奖金部分,但我第一部分完成的方式如下:

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

答案 6 :(得分:0)

这是一个简单的解决方案:

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}

成功!