有没有一种简便易行的方法来比较两个与Mathematica长度相同的列表?

时间:2021-07-09 14:01:38

Given two lists A={a1,a2,a3,...an} and B={b1,b2,b3,...bn}, I would say A>=B if and only if all ai>=bi.

给了两个列表= { a1,a2,a3,…一个}和B = { b1,b2,b3,……bn},当且仅当所有ai>=bi。

There is a built-in logical comparison of two lists, A==B, but no A>B. Do we need to compare each element like this

有两个列表的内置逻辑比较,a =B,但没有>B。我们需要像这样比较每个元素吗

And@@Table[A[[i]]>=B[[i]],{i,n}]

And@@Table[[[我]]> = B[[我]]{我n }]

Any better tricks to do this?

还有更好的方法吗?

EDIT: Great thanks for all of you.

编辑:非常感谢大家。

Here's a further question:

这是一个进一步的问题:

How to find the Maximum list (if exist) among N lists?

如何在N个列表中找到最大列表(如果存在)?

Any efficient easy way to find the maximum list among N lists with the same length using Mathematica?

有什么简单有效的方法可以用Mathematica在N个相同长度的列表中找到最大列表吗?

5 个解决方案

#1


18  

Method 1: I prefer this method.

方法一:我喜欢这种方法。

NonNegative[Min[a - b]]

Method 2: This is just for fun. As Leonid noted, it is given a bit of an unfair advantage for the data I used. If one makes pairwise comparisons, and return False and Break when appropriate, then a loop may be more efficient (although I generally shun loops in mma):

方法二:这只是为了好玩。正如列昂尼德指出的,我使用的数据给了它一些不公平的优势。如果进行成对比较,返回False并在适当的时候中断,那么循环可能会更有效(尽管我通常在mma中避免循环):

result = True;
n = 1; While[n < 1001, If[a[[n]] < b[[n]], result = False; Break[]]; n++]; result

Some timing comparisons on lists of 10^6 numbers:

一些时间比较列表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

有没有一种简便易行的方法来比较两个与Mathematica长度相同的列表?


Edit: I removed the timings for my Method #2, as they can be misleading. And Method #1 is more suitable as a general approach.

编辑:我删除了方法#2的时间,因为它们可能具有误导性。方法1更适合作为一种通用的方法。

#2


8  

For instance,

例如,

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"
  ]

is 20 times faster. 20 times uglier, too, though.

是20倍。但也有20倍的丑。

EDIT 2: Since David does not have a C compiler available, here are all the timing results, with two differences. Firstly, his second method has been fixed to compare all elements. Secondly, I compare a to itself, which is the worst case (otherwise, my second method above will only have to compare elements up to the first to violate the condition).

编辑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

有没有一种简便易行的方法来比较两个与Mathematica长度相同的列表?

So the compiled method is much faster (note that David's second method and the compiled method here are the same algorithm, and the only difference is overhead).

因此编译的方法要快得多(注意,David的第二方法和这里的编译方法是相同的算法,惟一的区别是开销)。

All these are on battery power so there may be some random fluctuations, but I think they are representative.

所有这些都是在电池功率上,所以可能会有一些随机波动,但我认为它们是有代表性的。

EDIT 3: If, as ruebenko suggested in a comment, I replace Part with Compile`GetElement, like this

编辑3:如果像ruebenko在评论中建议的那样,我用编译'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"]

then cmp2 is a twice as fast as cmp.

那么cmp2是cmp的两倍快。

#3


4  

Since you mentioned efficiency as a factor in your question, you may find these functions useful:

既然你在你的问题中提到效率,你可能会发现这些功能是有用的:

ClearAll[lessEqual, greaterEqual];
lessEqual[lst1_, lst2_] :=
   SparseArray[1 - UnitStep[lst2 - lst1]]["NonzeroPositions"] === {};

greaterEqual[lst1_, lst2_] :=
   SparseArray[1 - UnitStep[lst1 - lst2]]["NonzeroPositions"] === {};

These functions will be reasonably efficient. The solution of @David is still two-four times faster, and if you want extreme speed and your lists are numerical (made of Integer or Real numbers), you should probably use compilation to C (the solution of @acl and similarly for other operators).

这些函数将具有合理的效率。@David的解决方案仍然要快2 - 4倍,如果您想要极速并且您的列表是数值的(由整数或实数组成),您可能应该使用编译到C (@acl的解决方案,其他操作符也是如此)。

You can use the same techniques (using Unitize instead of UnitStep to implement equal and unequal), to implement other comparison operators (>, <, ==, !=). Keep in mind that UnitStep[0]==1.

您可以使用相同的技术(使用Unitize代替UnitStep来实现相等和不相等)来实现其他比较操作符(>,<,==,!=)。记住,UnitStep[0]= 1。

#4


3  

Comparison functions like Greater, GreaterEqual, Equal, Less, LessEqual can be made to apply to lists in a number of ways (they are all variations of the approach in your question).

比较函数如Greater、GreaterEqual、Equal、Equal、Less、LessEqual可以用多种方式应用于列表(它们都是问题中方法的变体)。

With two lists:

两个列表:

 a={a1,a2,a3};
 b={b1,b2,b3};

and two instances with numeric entries

和两个具有数字项的实例

na={2,3,4}; nb={1,3,2}; 

you can use

您可以使用

And@@NonNegative[na-nb]

With lists with symoblic entries

带有symoblic条目的列表。

And@@NonNegative[na-nb]

gives

给了

NonNegative[a1 - b1] && NonNegative[a2 - b2] && NonNegative[a3 - b3]

For general comparisons, one can create a general comparison function like

对于一般比较,可以创建一个一般的比较函数。

listCompare[comp_ (_Greater | _GreaterEqual | _Equal | _Less | _LessEqual), 
         list1_List, list2_List] := And @@ MapThread[comp, {list1, list2}]

Using as

使用

listCompare[GreaterEqual,na,nb]

gives True. With symbolic entries

给真实的。与象征性的条目

listCompare[GreaterEqual,a,b]

gives the logially equivalent expression a1 <= b1 && a2 <= b2 && a3 <= b3.

给出逻辑等效表达式a1 <= b1 & a2 <= b2 & a3 <= b3。

#5


2  

When working with packed arrays and numeric comparator such as >= it would be hard to beat David's Method #1.

当使用压缩数组和数值比较器(如>=)时,很难击败David的方法#1。

However, for more complicated tests that cannot be converted to simple arithmetic another method is required.

但是,对于不能转换为简单算术的更复杂的测试,则需要另一种方法。

A good general method, especially for unpacked lists, is to use Inner:

一个好的通用方法,特别是对于未打包的列表,是使用Inner:

Inner[test, a, b, And]

This does not make all of the comparisons ahead of time and can therefore be much more efficient in some cases than e.g. And @@ MapThread[test, {a, b}]. This illustrates the difference:

这并不能使所有的比较提前,因此在某些情况下比例如@ 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

If the arrays are packed and especially if the likelihood that the return is False is high then a loop such as David's Method #2 is a good option. It may be better written:

如果数组被打包,特别是如果返回值为False的可能性很高,那么像David的方法#2这样的循环是一个很好的选择。最好这样写:

Null === Do[If[a[[i]] ~test~ b[[i]], , Return@False], {i, Length@a}]
1 >= 1
2 >= 3

False

#1


18  

Method 1: I prefer this method.

方法一:我喜欢这种方法。

NonNegative[Min[a - b]]

Method 2: This is just for fun. As Leonid noted, it is given a bit of an unfair advantage for the data I used. If one makes pairwise comparisons, and return False and Break when appropriate, then a loop may be more efficient (although I generally shun loops in mma):

方法二:这只是为了好玩。正如列昂尼德指出的,我使用的数据给了它一些不公平的优势。如果进行成对比较,返回False并在适当的时候中断,那么循环可能会更有效(尽管我通常在mma中避免循环):

result = True;
n = 1; While[n < 1001, If[a[[n]] < b[[n]], result = False; Break[]]; n++]; result

Some timing comparisons on lists of 10^6 numbers:

一些时间比较列表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

有没有一种简便易行的方法来比较两个与Mathematica长度相同的列表?


Edit: I removed the timings for my Method #2, as they can be misleading. And Method #1 is more suitable as a general approach.

编辑:我删除了方法#2的时间,因为它们可能具有误导性。方法1更适合作为一种通用的方法。

#2


8  

For instance,

例如,

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"
  ]

is 20 times faster. 20 times uglier, too, though.

是20倍。但也有20倍的丑。

EDIT 2: Since David does not have a C compiler available, here are all the timing results, with two differences. Firstly, his second method has been fixed to compare all elements. Secondly, I compare a to itself, which is the worst case (otherwise, my second method above will only have to compare elements up to the first to violate the condition).

编辑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

有没有一种简便易行的方法来比较两个与Mathematica长度相同的列表?

So the compiled method is much faster (note that David's second method and the compiled method here are the same algorithm, and the only difference is overhead).

因此编译的方法要快得多(注意,David的第二方法和这里的编译方法是相同的算法,惟一的区别是开销)。

All these are on battery power so there may be some random fluctuations, but I think they are representative.

所有这些都是在电池功率上,所以可能会有一些随机波动,但我认为它们是有代表性的。

EDIT 3: If, as ruebenko suggested in a comment, I replace Part with Compile`GetElement, like this

编辑3:如果像ruebenko在评论中建议的那样,我用编译'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"]

then cmp2 is a twice as fast as cmp.

那么cmp2是cmp的两倍快。

#3


4  

Since you mentioned efficiency as a factor in your question, you may find these functions useful:

既然你在你的问题中提到效率,你可能会发现这些功能是有用的:

ClearAll[lessEqual, greaterEqual];
lessEqual[lst1_, lst2_] :=
   SparseArray[1 - UnitStep[lst2 - lst1]]["NonzeroPositions"] === {};

greaterEqual[lst1_, lst2_] :=
   SparseArray[1 - UnitStep[lst1 - lst2]]["NonzeroPositions"] === {};

These functions will be reasonably efficient. The solution of @David is still two-four times faster, and if you want extreme speed and your lists are numerical (made of Integer or Real numbers), you should probably use compilation to C (the solution of @acl and similarly for other operators).

这些函数将具有合理的效率。@David的解决方案仍然要快2 - 4倍,如果您想要极速并且您的列表是数值的(由整数或实数组成),您可能应该使用编译到C (@acl的解决方案,其他操作符也是如此)。

You can use the same techniques (using Unitize instead of UnitStep to implement equal and unequal), to implement other comparison operators (>, <, ==, !=). Keep in mind that UnitStep[0]==1.

您可以使用相同的技术(使用Unitize代替UnitStep来实现相等和不相等)来实现其他比较操作符(>,<,==,!=)。记住,UnitStep[0]= 1。

#4


3  

Comparison functions like Greater, GreaterEqual, Equal, Less, LessEqual can be made to apply to lists in a number of ways (they are all variations of the approach in your question).

比较函数如Greater、GreaterEqual、Equal、Equal、Less、LessEqual可以用多种方式应用于列表(它们都是问题中方法的变体)。

With two lists:

两个列表:

 a={a1,a2,a3};
 b={b1,b2,b3};

and two instances with numeric entries

和两个具有数字项的实例

na={2,3,4}; nb={1,3,2}; 

you can use

您可以使用

And@@NonNegative[na-nb]

With lists with symoblic entries

带有symoblic条目的列表。

And@@NonNegative[na-nb]

gives

给了

NonNegative[a1 - b1] && NonNegative[a2 - b2] && NonNegative[a3 - b3]

For general comparisons, one can create a general comparison function like

对于一般比较,可以创建一个一般的比较函数。

listCompare[comp_ (_Greater | _GreaterEqual | _Equal | _Less | _LessEqual), 
         list1_List, list2_List] := And @@ MapThread[comp, {list1, list2}]

Using as

使用

listCompare[GreaterEqual,na,nb]

gives True. With symbolic entries

给真实的。与象征性的条目

listCompare[GreaterEqual,a,b]

gives the logially equivalent expression a1 <= b1 && a2 <= b2 && a3 <= b3.

给出逻辑等效表达式a1 <= b1 & a2 <= b2 & a3 <= b3。

#5


2  

When working with packed arrays and numeric comparator such as >= it would be hard to beat David's Method #1.

当使用压缩数组和数值比较器(如>=)时,很难击败David的方法#1。

However, for more complicated tests that cannot be converted to simple arithmetic another method is required.

但是,对于不能转换为简单算术的更复杂的测试,则需要另一种方法。

A good general method, especially for unpacked lists, is to use Inner:

一个好的通用方法,特别是对于未打包的列表,是使用Inner:

Inner[test, a, b, And]

This does not make all of the comparisons ahead of time and can therefore be much more efficient in some cases than e.g. And @@ MapThread[test, {a, b}]. This illustrates the difference:

这并不能使所有的比较提前,因此在某些情况下比例如@ 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

If the arrays are packed and especially if the likelihood that the return is False is high then a loop such as David's Method #2 is a good option. It may be better written:

如果数组被打包,特别是如果返回值为False的可能性很高,那么像David的方法#2这样的循环是一个很好的选择。最好这样写:

Null === Do[If[a[[i]] ~test~ b[[i]], , Return@False], {i, Length@a}]
1 >= 1
2 >= 3

False