从列表列表中按最后一个元素选择最大值的最佳方法是什么?

时间:2011-07-12 03:35:33

标签: wolfram-mathematica

在Mathematica中,Max[]是获取数字列表中最大数字的最有效函数,但是如何找到列表列表中包含最大最后一个元素的列表?例如在一系列坐标中具有最大x部分的二维坐标。

我最好的尝试是SortBy,但显然我不需要程序来排序我的列表,只需要我需要的最大值。

6 个答案:

答案 0 :(得分:6)

也许:

list = {{4, 3}, {5, 10}, {-2, 1}, {3, 7}}

Reverse /@ Take[#, Ordering[#, -1]] &@(Reverse /@ #) &@ list
(*
-> {{5, 10}}
*)

利用Ordering[ ]命令列出第一个元素

的事实

修改

或者更好(我认为):

Take[#, Ordering[Last /@ #, -1]] &@ list

修改

此外:

#[[Ordering[#, -1, Last@#2 > Last@#1 &]]] &@list

修改

也许更快:

#[[First@Position[#, Max@#] &@(Last /@ #)]] &@list

答案 1 :(得分:4)

以下是使用Pick

的方法
maxBy[list_, n_] := With[{s = list[[All, n]]}, Pick[list, s, Max[s]]]

maxBy[{{4, 3}, {5, 10}, {-2, 1}, {3, 7}}, 2]

(* output: 
  {{5, 10}}  
*)

此版本适用于每个子列表中的任意数量的元素,n小于或等于最短子列表的长度。

我机器上此版本的计时

list2 = RandomInteger[{-10^7, 10^7}, {10^6, 2}];
list3 = RandomInteger[{-10^7, 10^7}, {10^6, 3}];
list9 = RandomInteger[{-10^7, 10^7}, {10^6, 9}];

maxBy[list2, 2]; // Timing
maxBy[list3, 2]; // Timing
maxBy[list9, 2]; // Timing

(* output: 
  {0.030341, Null}  
  {0.030912, Null}  
  {0.033313, Null}  
*)

与David的代码相比

maxBy[list2, 2]; // Timing
maxBy[list3, 2]; // Timing
maxBy[list9, 2]; // Timing

(* ouput:
  {0.186175, Null}  
  {0.184989, Null}  
  {0.262018, Null}  
*)
尤达的代码

maxBy[list2, 2]; // Timing
maxBy[list3, 2]; // Timing
maxBy[list9, 2]; // Timing

(* ouput:
  {0.944016, Null}
  {0.83094, Null}
  {0.874126, Null}
*)

和belisarius'代码

Reverse /@ Take[#, Ordering[#, -1]] &@(Reverse /@ #) &@list2; // Timing
Take[#, Ordering[Last /@ #, -1]] &@list2; // Timing
#[[Ordering[#, -1, Last@#2 > Last@#1 &]]] &@list2; // Timing
#[[First@Position[#, Max@#] &@(Last /@ #)]] &@list2; // Timing 

(* output:
  {0.211016, Null}
  {0.099253, Null}
  {2.03415, Null}
  {0.266934, Null}
*)

答案 2 :(得分:1)

这个函数怎么样(这里仅为2D列表定义):

maxBy = Module[{pattern = Reverse@Insert[{Max@#1[[All, #2]]}, _, #2]},
               Cases[#1, pattern]] &

实施例

list = {{4, 3}, {5, 10}, {20, 1}, {3, 7}};

maxBy[list, 1]    
Out[1]= {{20, 1}}

maxBy[list, 2]  
Out[2]= {{5, 10}}

答案 3 :(得分:1)

这是一种依赖于Transpose的方法:

maxBy = #1[[Position[t = Transpose[#1][[#2]], Max[t]][[All, 1]]]] &;

例如:     list = {{4,3},{5,10},{20,1},{3,7}};

maxBy[list, 1]
(* {{20, 1}}   *)

maxBy[list, 2]
(* {{5, 10}} *)

每个子列表可以处理两个以上的元素,前提是这些子列表的长度都相同。

r:=RandomInteger[{-10^5,10^5}];
list3=Table[{r,r,r},{j,10^2}];             (* 3 numbers in each sublist *)
list9=Table[{r,r,r,r,r,r,r,r,r},{j,10^2}]; (* 9 numbers *)

maxBy[list3, 2]     (* Find max in position 2 of list3 *)
(* {{-93332, 99582, 4324}}  *)

maxBy[list9, 5]     (* Find max in position 5 of list9 *)
(* {{7680, 85508, 51915, -58282, 94679, 50968, -12664, 75246, -82903}} *)

当然,结果会根据您生成的随机数而有所不同。

修改

这是大型列表的一些时序数据。 SortBy明显变慢了。但似乎并不受每个子列表中元素数量的影响。首先,我的maxBy代码后跟SortBy

Timing comparison

使用相同的list2,这是Yoda代码的一些时序数据。虽然他的例程也被称为maxBy,但是他产生了以下输出:

Yoda

同样,使用相同的list2,Belisarius代码的一些数据:

Belisarius

他的第二个建议是所有测试中最快的。

答案 4 :(得分:1)

不是最有效但更简单的吗?

max = Max@list[[All, -1]];
Cases[list, {_, max}]

max = Max@list3[[All, -1]];
Cases[list3, {_,_, max}]

<强>用法

list = {{40, 3}, {5, 10}, {-2, 1}, {3, 10}}

max = Max@list[[All, -1]];
Cases[list, {_, max}]

输出:

{{5, 10}, {3, 10}}

答案 5 :(得分:1)

在阅读了一些文档并做了一些实验后,我设法更清楚地了解了这个问题。

我实际上想知道为什么Max[]似乎故意避免提供指令,使其不仅返回max元素本身,还返回其位置。毕竟,提供位置不会改变算法的O(n)复杂度。例如,想象一下:

In[1]:= Max[{991, 993, 992}, ReturnPosition -> True]

Out[1]= {2}

如果可以,您可以使用下面的代码来解决我的问题:

list[[Max[list[[All, -1]], ReturnPosition -> True]]]

但是现在我意识到系统函数Max[]而不是设计用于查找列表中的max元素。你可以看出,Wolfram团队显然使Max[]更像是数学中的传统max函数 - 它做了简单的符号简化,它自动展平了所有列表,它可以在一个可绘制的函数中,并且大多数重要的是,它是Orderless

In[2]:= Attributes[Max]

Out[2]= {Flat, NumericFunction, OneIdentity, Orderless, Protected}

这使得职位毫无意义。总之,它将内部的所有列表视为数学集。

因此,哲学上Mathematica计算它并非易事。我需要做的就是“DIY”一个具有O(n)复杂性的功能,并且可以完成这项工作。我认为TomD正朝着正确的方向前进,尽管我更喜欢:

maxLast[l_] := Cases[l, {___, Max[Last/@l]}]

和Heike(黑客?)采用Pick可能有更好的技术专门用于选择元素,但算法的复杂性必须没有虚拟差异。我可以用这种方式重写它:(名字和头部越少,速度越快)

maxLast[l_] := Pick[l, #, Max[#]] &[Last /@ l]

他们都是很好的答案。