【问题标题】:Map Select for Conditional Query in MathematicaMathematica 中条件查询的映射选择
【发布时间】:2011-06-04 05:06:01
【问题描述】:

使用以下列表,

list = {{a, b, c, d}, {1, 2, 3, 4}, {5, 6, 7, 8}};

是否可以选择第二个值大于 3 的列表。所需的输出如下

{5, 6, 7, 8}

调整以下当前提取列表中所有值>2的代码

Select[#, # > 2 &] & /@ list[[2 ;;]

查询的复杂解决方案可以在这里找到Conditional Data Manipulation in Mathematica

【问题讨论】:

  • SelectCases 之间是否存在性能差异?
  • @d00b Select 对于此类任务通常比 Cases 快。在这种特殊情况下,Select 是最佳选择。

标签: dictionary select wolfram-mathematica


【解决方案1】:

或者,使用Select

Select[list, #[[2]] > 3 &]

输出

{{5, 6, 7, 8}}

【讨论】:

  • 我发现这非常强大且易于理解。您能否对其进行调整以指定要提取的列表中的元素。对于上述问题,这可能是一个简单的附加解决方案。谢谢!
  • @500,你的意思是你要比较的元素(第二列),还是你想要输出的一个子集,比如{6, 7, 8}
  • @500。期望输出的一个例子会很棒。 Select 可以接受第三个参数可能会很有趣。 Select[list, MemberQ[#, 5] &] 返回所有包含 5 的子列表,Select[list, MemberQ[#, 5] &, 1] 返回包含 5 的 first 子列表。
  • @Mr.Wizard : 两者都有,看看 Select 能有多灵活。
【解决方案2】:

在这种情况下Select 是最简单的方法,但Pick 也可以用于相关问题。

list = {{a, b, c, d}, {1, 2, 3, 4}, {5, 6, 7, 8}};

Pick[list, #>3& /@ list[[All, 2]] ]

解释一下,Pick 接受两个相同形状的列表(或嵌套列表),并返回第一个中的每个元素,第二个的对应元素是 True。 (它也可以接受第三个参数来匹配True以外的元素。)

这里,用list[[All, 2]] 提取第二列,然后将测试#>3& 映射到每个元素。然后将其用作选择列表。


响应 cmets 500 请求泛化Select 方法:

selectByColumn[array_, index_, value_, range_] :=
  Select[array, #[[index]] > value &][[All, range]]

这允许人们指定:

  • array : 要从中提取的输入数组
  • index : 用于比较的列索引
  • value :要比较的值
  • range :要从每个结果行中提取的 Part 规范

【讨论】:

    【解决方案3】:

    不同方案的速度比较

    有趣的是,Select 总是使用解压数组更快地工作,而对于大型数组,差异大约是一个数量级!点击下表放大:

    计时测试代码:

    solutions = Hold[
       Select[list, #[[2]] > 3 &],
       Cases[list, _List?(#[[2]] > 3 &)],
       Cases[list, x_List /; x[[2]] > 3],
       Cases[list, {_, x_, ___} /; x > 3],
       Cases[list, {_, _?(# > 3 &), ___}],
       Cases[list, {x___} /; List[x][[2]] > 3],
       Pick[list, UnitStep[list[[All, 2]] - 3], 1],
       Pick[list, # > 3 & /@ list[[All, 2]]]
       ];
    testCases = Hold[
       {"Packed Reals", RandomReal[{0, 5}, {dim, dim}]},
       {"Unpacked Reals", 
        Developer`FromPackedArray@RandomReal[{0, 5}, {dim, dim}]},
       {"Packed Integers", RandomInteger[{0, 5}, {dim, dim}]},
       {"Unpacked Integers", 
        Developer`FromPackedArray@RandomInteger[{0, 5}, {dim, dim}]},
       {"Rationals", 
        Rationalize[#, .001] & /@ RandomReal[{0, 5}, {dim, dim}]}
       ];
    timing := 
      Function[Null, 
       If[(time = First[Timing[Do[#;, {n}]]]) < .3, 
         Print["Too small timing for ", n, " iterations (dim=", dim, 
          ") of ", HoldForm[#], ": ", time, " seconds!"]; time, time]/n, 
       HoldFirst];
    generateTable := 
     Labeled[TableForm[
       Transpose@
        Table[list = testCases[[i, 2]]; 
         tmgs = List @@ (timing /@ solutions); 
         d = Last@MantissaExponent[Min[tmgs]] - 3; 
         Row[{Round[10^-d*#], ".\[Times]", Superscript[10, d]}] & /@ 
          tmgs, {i, 1, Length[testCases]}], 
       TableHeadings -> {List @@ (HoldForm /@ solutions), 
         List @@ testCases[[All, 1]]}, TableAlignments -> Right], 
      Row[{"Average timings for ", dim, "\[Times]", dim, " list"}], Top]
    
    Column[{dim = 5; n = 30000; generateTable, dim = 100; n = 3000; 
      generateTable, dim = 1000; n = 150; generateTable}, Left, 1, 
     Frame -> All, FrameStyle -> Gray]
    

    【讨论】:

    • 您能否将Pick[list, UnitStep[list[[All, 2]] - 3], 1] 添加到您的测试列表中。不像其他的那么清晰,但是很快。
    【解决方案4】:

    另一种 Cases 语法。第一项被跳过,第二项被测试为> 3,我们不关心列表的其余部分:

    In[45]:= Cases[list, {_, _?(# > 3 &), ___}]
    Out[45]= {{5, 6, 7, 8}}
    

    我怀疑这会比 Select 更快,但有时会更清晰,特别是如果测试涉及不同的数据类型或匹配某些子结构。

    【讨论】:

      【解决方案5】:

      编辑:

      正如 Alexey 所说,以下结构在 Mathematica 中比我之前的解决方案更惯用

      Cases[list, x_List /; x[[2]] > 2]
      

      Cases[list, _List?(#[[2]] > 2 &)]
      

      一种解决方案是使用Cases

      Cases[list, {_, x_, ___} /; x > 2]
      Out[1] = {{5, 6, 7, 8}}
      

      如果您想(比如说)检查第 95 个元素是否 > 2,这将没有帮助。所以这是一种更好的方法,您可以轻松地指定位置:

      Cases[list, {x___} /; List[x][[2]] > 2]
      Out[2] = {{5, 6, 7, 8}}
      

      【讨论】:

      • 你可以写得更短:Cases[list, x_List /; x[[2]] &gt; 2] 甚至Cases[list, _List?(#[[2]] &gt; 2 &amp;)]
      • @Alexey:谢谢。一般来说,你给出的两个结构是更快还是只是出于对简洁的热爱?
      • @yoda 我没有测试它们的速度,但是这两个结构都应该比你的更快。他们提出了在 Mathematica 中做这些事情的更正确的方法。
      • @yoda 我刚刚做了时间测试。最快的构造是Cases[list, _List?(#[[2]] &gt; 2 &amp;)],但Cases[list, x_List /; x[[2]] &gt; 2] 比你的Cases[list, {_, x_, ___} /; x &gt; 2] 慢一点(20 到 19),同时更通用。
      • @yoda 有趣的是,对于大量的机器编号 lists (Developer`PackedArrayQ),您的构造 Cases[list, {_, x_, ___} /; x &gt; 2] 不仅比我的快,而且比 Select[list, #[[2]] &gt; 2 &amp;] 快。但对于 Rationals 的大 lists 和非打包数组,它相应地慢 30 倍和 17 倍。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-15
      • 1970-01-01
      • 2022-01-08
      • 1970-01-01
      • 2011-08-10
      • 1970-01-01
      相关资源
      最近更新 更多