鉴于两个列表A={a1,a2,a3,...an}
和B={b1,b2,b3,...bn}
,我会说A>=B
当且仅当所有ai>=bi
。
两个列表A==B
存在内置逻辑比较,但没有A>B
。
我们是否需要像这样比较每个元素
And@@Table[A[[i]]>=B[[i]],{i,n}]
有什么更好的技巧吗?
修改 非常感谢大家。
这是另一个问题:
如何在N个列表中找到最大列表(如果存在)?
答案 0 :(得分:18)
方法1 :我更喜欢这种方法。
NonNegative[Min[a - b]]
方法2 :这只是为了好玩。正如列昂尼德指出的那样,对于我使用的数据,它有一些不公平的优势。 如果进行成对比较,并在适当时返回False和Break, 然后循环可能更有效(虽然我通常避免在mma中循环):
result = True;
n = 1; While[n < 1001, If[a[[n]] < b[[n]], result = False; Break[]]; n++]; result
对10 ^ 6个数字列表进行一些时序比较:
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
编辑:我删除了方法#2的时间,因为它们可能会产生误导。方法#1更适合作为一般方法。
答案 1 :(得分:8)
例如,
And @@ Thread[A >= B]
应该做的。
编辑:另一方面,这个
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
的两倍。
答案 2 :(得分:4)
由于您提到效率是问题的一个因素,您可能会发现这些功能很有用:
ClearAll[lessEqual, greaterEqual];
lessEqual[lst1_, lst2_] :=
SparseArray[1 - UnitStep[lst2 - lst1]]["NonzeroPositions"] === {};
greaterEqual[lst1_, lst2_] :=
SparseArray[1 - UnitStep[lst1 - lst2]]["NonzeroPositions"] === {};
这些功能将相当有效。 @David的解决方案仍然快两到四倍,如果你想要极速并且你的列表是数字的(由整数或实数组成),你应该使用编译到C(@acl的解决方案和类似的其他运算符)。
您可以使用相同的技巧(使用Unitize
代替UnitStep
来实现equal
和unequal
),以实现其他比较运算符(>
, <
,==
,!=
)。请记住UnitStep[0]==1
。
答案 3 :(得分:3)
可以使用Greater, GreaterEqual, Equal, Less, LessEqual
等比较函数以多种方式应用于列表(它们都是您问题中方法的变体)。
有两个清单:
a={a1,a2,a3};
b={b1,b2,b3};
和两个带数字条目的实例
na={2,3,4}; nb={1,3,2};
你可以使用
And@@NonNegative[na-nb]
带有symoblic条目的列表
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}]
使用
listCompare[GreaterEqual,na,nb]
给出True
。带符号条目
listCompare[GreaterEqual,a,b]
给出逻辑等效的表达式a1 <= b1 && a2 <= b2 && a3 <= b3
。
答案 4 :(得分:2)
使用压缩数组和数字比较器(如>=
)时,很难击败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的Method#2之类的循环是一个不错的选择。可能写得更好:
Null === Do[If[a[[i]] ~test~ b[[i]], , Return@False], {i, Length@a}]
1 >= 1 2 >= 3 False