给定两个列表A={a1,a2,a3,...an}
和B={b1,b2,b3,...bn}
,当且仅当所有的ai>=bi
时,我将说A>=B
。
虽然有内置的逻辑比较两个列表的操作A==B
,但没有A>B
这种形式。我们需要像下面这样逐个元素地进行比较吗?
And@@Table[A[[i]]>=B[[i]],{i,n}]
还有更好的方法吗?
编辑: 非常感谢大家。
以下是进一步的问题:
如何在N个相同长度的列表中找到最大的一个(如果存在)?
给定两个列表A={a1,a2,a3,...an}
和B={b1,b2,b3,...bn}
,当且仅当所有的ai>=bi
时,我将说A>=B
。
虽然有内置的逻辑比较两个列表的操作A==B
,但没有A>B
这种形式。我们需要像下面这样逐个元素地进行比较吗?
And@@Table[A[[i]]>=B[[i]],{i,n}]
还有更好的方法吗?
编辑: 非常感谢大家。
以下是进一步的问题:
如何在N个相同长度的列表中找到最大的一个(如果存在)?
方法 1:我更喜欢这种方法。
NonNegative[Min[a - b]]
方法 2: 这只是为了好玩。正如Leonid所指出的那样,对于我使用的数据,它给了一点不公平的优势。 如果进行成对比较,并在适当时返回 False 和 Break, 那么循环可能更有效(尽管我通常避免在mma中使用循环):
result = True;
n = 1; While[n < 1001, If[a[[n]] < b[[n]], result = False; Break[]]; n++]; result
a = Table[RandomInteger[100], {10^6}];
b = Table[RandomInteger[100], {10^6}];
(* OP's method *)
And @@ Table[a[[i]] >= b[[i]], {i, 10^6}] // Timing
(* acl's uncompiled method *)
And @@ Thread[a >= b] // Timing
(* Leonid's method *)
lessEqual[a, b] // Timing
(* David's method #1 *)
NonNegative[Min[a - b]] // Timing
编辑:我已经移除了Method #2的时间数据,因为它们可能会误导人。Method #1更适合作为一般方法。
And @@ Thread[A >= B]
should do the job.
EDIT: On the other hand, this
cmp = Compile[
{
{a, _Integer, 1},
{b, _Integer, 1}
},
Module[
{flag = True},
Do[
If[Not[a[[p]] >= b[[p]]], flag = False; Break[]],
{p, 1, Length@a}];
flag],
CompilationTarget \[Rule] "C"
]
速度快20倍。但丑陋了20倍。
编辑2:由于David没有C编译器可用,这里列出了所有的时间结果,有两个差异。首先,他的第二种方法已经被修复以比较所有元素。其次,我将a
与自身进行比较,这是最坏的情况(否则,上面我的第二种方法只需要比较到第一个违反条件的元素)。
(*OP's method*)
And @@ Table[a[[i]] >= b[[i]], {i, 10^6}] // Timing
(*acl's uncompiled method*)
And @@ Thread[a >= b] // Timing
(*Leonid's method*)
lessEqual[a, b] // Timing
(*David's method #1*)
NonNegative[Min[a - b]] // Timing
(*David's method #2*)
Timing[result = True;
n = 1; While[n < Length[a],
If[a[[n]] < b[[n]], result = False; Break[]];
n++]; result]
(*acl's compiled method*)
cmp[a, a] // Timing
因此,编译后的方法要快得多(请注意,David的第二种方法和此处的编译方法是相同的算法,唯一的区别是开销)。
所有这些都是在电池供电的情况下进行的,因此可能会有一些随机波动,但我认为它们是代表性的。
编辑3:如果像ruebenko在评论中建议的那样,将Part
替换为Compile`GetElement
,就像这样:
cmp2 = Compile[{{a, _Integer, 1}, {b, _Integer, 1}},
Module[{flag = True},
Do[If[Not[Compile`GetElement[a, p] >= Compile`GetElement[b, p]],
flag = False; Break[]], {p, 1, Length@a}];
flag], CompilationTarget -> "C"]
cmp2
比cmp
快两倍。cmp1 = Compile[{{a, _Integer, 1}, {b, _Integer, 1}}, Do[If[a[[p]] < b[[p]], Return[False]], {p, 1, Length@a}] != False, CompilationTarget -> "C"]
。 - Leonid ShifrinDeveloper
PackedArrayQ[a - b]返回了
True`,所以速度这么快。 - aclcmp
相同)。特别是通过 ruebenko 的未记录技巧! - acl既然你在问题中提到了效率,那么以下这些函数可能会对你有帮助:
ClearAll[lessEqual, greaterEqual];
lessEqual[lst1_, lst2_] :=
SparseArray[1 - UnitStep[lst2 - lst1]]["NonzeroPositions"] === {};
greaterEqual[lst1_, lst2_] :=
SparseArray[1 - UnitStep[lst1 - lst2]]["NonzeroPositions"] === {};
SparseArray
的使用方式,但我同意您的解决方案更优秀。 - Leonid ShifrinlargeTst1 = RandomInteger[1000, 10000000];largeTst2 = RandomInteger[{999, 1990}, 10000000];In[95]:= NonNegative[Min[largeTst2-largeTst1]]//Timing Out[95]= {0.125,False}; In[96]:= greaterEqual[largeTst2,largeTst1]//Timing Out[96]= {0.234,False}
。 - Leonid Shifrin a={a1,a2,a3};
b={b1,b2,b3};
并且有两个数字条目的实例
na={2,3,4}; nb={1,3,2};
你可以使用
And@@NonNegative[na-nb]
And@@NonNegative[na-nb]
提供
NonNegative[a1 - b1] && NonNegative[a2 - b2] && NonNegative[a3 - b3]
对于一般的比较,可以创建一个通用的比较函数,如下所示:
listCompare[comp_ (_Greater | _GreaterEqual | _Equal | _Less | _LessEqual),
list1_List, list2_List] := And @@ MapThread[comp, {list1, list2}]
使用 as 关键字
listCompare[GreaterEqual,na,nb]
使用符号输入,True
返回。
listCompare[GreaterEqual,a,b]
给出逻辑上等价的表达式 a1 <= b1 && a2 <= b2 && a3 <= b3
。
当处理打包数组和数值比较器(如>=
)时,使用David的方法#1难以超越。
但是,对于无法转换为简单算术的更复杂的测试,需要另一种方法。
一个很好的通用方法,特别适用于未打包的列表,是使用Inner
:
Inner[test, a, b, And]
这种方法不事先进行所有比较,因此在某些情况下比例如And @@ MapThread[test, {a, b}]
更加高效。以下是两者之间的区别:
test = (Print[#, " >= ", #2]; # >= #2) &;
{a, b} = {{1, 2, 3, 4, 5}, {1, 3, 3, 4, 5}};
Inner[test, a, b, And]
1 >= 1 2 >= 3 False
And @@ MapThread[test, {a, b}]
如果数组被压缩,尤其是当返回值为1 >= 1 2 >= 3 3 >= 3 4 >= 4 5 >= 5 False
False
的可能性较高时,像David's Method #2这样的循环是一个不错的选择。最好将代码编写为:Null === Do[If[a[[i]] ~test~ b[[i]], , Return@False], {i, Length@a}]
1 >= 1 2 >= 3 False
Inner
的好提示,我之前不知道它的效率优势,+1) - acla
并设置b=a
,那么解包列表版本比打包的版本稍微慢一点。也就是说,打包并不会真正影响Do
等函数的性能(尽管它们似乎没有解包)。或者我误解了吗? - acl