我有一个列表,我想对每个元素应用逻辑测试,如果其中任何一个元素不满足这个条件,则返回false。我想在Mathematica中写这个或找到一个内置函数,但似乎ForAll
实际上并没有这样做。
我的问题是:如何最有效地完成这项工作?
奖励:Exists
函数的类似情况如何:即如果列表中有任何元素满足条件,则返回true。
答案 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
的第三个参数中,那么下面的内容可能会有用。
要执行此操作,您需要了解标准Or
和And
函数,以及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}
答案 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
(此处,timeIt
为this)。
答案 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)
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}
成功!