\begingroup

如何从以下列表中有效地选择具有第三个元素最小值的子列表?

longList = {{1, 1, 12}, {1, 2, 10}, {1, 3, 12}, {1, 4, 12}, {1, 5, 10}, 
            {2, 1, 10}, {2, 2, 8}, {2, 3, 10}, {2, 4, 10}, {2, 5, 8}, 
            {3, 1, 12}, {3, 2, 10}, {3, 3, 12}, {3, 4, 12}, {3, 5, 10}};
Select[longList, #[[3]] == Min[longList[[All, 3]]] &]

假设所有数字都是整数,并且这个数字longList相当大,包含大约 1 亿个元素。

\endgroup


6 个回答
6

\begingroup

随机数据

longList = RandomInteger[100, {1000,5}];

您的解决方案

AbsoluteTiming[
   Select[longList, #[[3]] == Min[longList[[All, 3]]] &]
]

(* {0.017431,{{100,81,0,36,91},{6,33,0,76,0},{9,9,0,19,16},{56,81,0,16,10},{72,31,0,9,3},{34,97,0,38,79},{53,93,0,32,37},{98,94,0,84,60}}}*)

我的解决方案

部分、位置

AbsoluteTiming[
   Part[#, Flatten@ Position[#[[All, 3]], Min[#[[All, 3]]]]]& @ longList
]

(* {0.000173,{{100,81,0,36,91},{6,33,0,76,0},{9,9,0,19,16},{56,81,0,16,10},{72,31,0,9,3},{34,97,0,38,79},{53,93,0,32,37},{98,94,0,84,60}}} *)

最小值,提取

MinimalBy[Extract[3]]@ longList

基准

theTrends =Transpose@Table[
    With[
        {longList = RandomInteger[100, {k,5}]},
        {
            {k, First@AbsoluteTiming@Select[longList, #[[3]] == Min[longList[[All, 3]]] &]}, (* OP *)
            {k, First@AbsoluteTiming[Part[#, Flatten@ Position[#[[All, 3]], Min[#[[All, 3]]]]]& @ longList]}, (* rhermans *)
            {k, First@AbsoluteTiming@MinimalBy[Extract[3]]@ longList}, (* rhermans *)
            {k, First@AbsoluteTiming@Pick[longList, longList[[All, 3]],   Min[longList[[All, 3]]]]}, (* "user1066" *)
            {k, First@AbsoluteTiming[MinimalBy[longList, #[[3]] &]@longList]} (* PlatoManiac *)
        }
    ]
    ,{k, PowerRange[2, 2^17, 2]}
];

\endgroup

1

  • \begingroup
    我也刚刚尝试了这种方法user1066,它似乎可以更快地处理大型列表。
    \endgroup


    – 

\begingroup

With[{x = longList[[All, 3]]}, Pick[longList, x, Min[x]]]

(* {{4, 29, 0, 15, 40}, {31, 3, 0, 3, 61}, {86, 12, 0, 13, 54},
    {48, 56, 0, 4, 94}, {19, 94, 0, 56, 28}, {90, 57, 0, 91,51}, 
    {76, 14, 0, 70, 84}} *)

原始答案

 Pick[longList, longList[[All, 3]], 
  Min[longList[[All, 3]]]] // AbsoluteTiming


(* {0.000064, {{4, 29, 0, 15, 40}, {31, 3, 0, 3, 61}, {86, 12, 0, 13, 
   54}, {48, 56, 0, 4, 94}, {19, 94, 0, 56, 28}, {90, 57, 0, 91, 
   51}, {76, 14, 0, 70, 84}}} *)

使用longlist由@rhermans 定义

longList = RandomInteger[100, {1000,5}];

Select[longList, #[[3]] == Min[longList[[All, 3]]] &] == 
  Pick[longList, longList[[All, 3]], Min[longList[[All, 3]]]]

(* True *) 

\endgroup

1

  • \begingroup
    在我的计算机上,这稍微快一些:With[{x = longList . {0, 0, 1, 0, 0}}, Pick[longList, x, Min[x]]]
    \endgroup


    – 

\begingroup

您的解决方案还不错,但问题在于Min[longList[[All, 3]]]对 longList 中的每个元素都重复进行评估。计算一次最小值:

longList = {{1, 1, 12}, {1, 2, 10}, {1, 3, 12}, {1, 4, 12}, {1, 5, 
    10}, {2, 1, 10}, {2, 2, 8}, {2, 3, 10}, {2, 4, 10}, {2, 5, 8}, {3,
     1, 12}, {3, 2, 10}, {3, 3, 12}, {3, 4, 12}, {3, 5, 10}};
min = Min[longList[[All, 3]]];
Select[longList, #[[3]] == min &] // AbsoluteTiming

{0.0000158, {{2, 2, 8}, {2, 5, 8}}}

\endgroup

1

  • \begingroup
    很好,我运行了 45 多分钟然后就停了下来,因为它太慢了。
    \endgroup


    – 

\begingroup

对于大型列表,这也应该可以相当快地工作。

longList = RandomInteger[100, {100000000, 5}];
MinimalBy[longList, #[[3]] &]; // AbsoluteTiming

{5.28234, 空}

\endgroup

\begingroup

抓取@rhermans 定义的长名单:

longList = RandomInteger[100, {1000,5}];

使用PositionSmallestExtract

Extract[longList, Outer[List, PositionSmallest[longList[[All, 3]]]]] ==
Pick[longList, longList[[All, 3]], Min[longList[[All, 3]]]]

(*True*)

\endgroup

0

\begingroup

使用ReapSowScan

 Reap[Scan[If[#[[3]] == Min[longList[[All, 3]]], Sow[#]] &, 
   longList]][[2, 1]]

\endgroup