Map Select for conditional query in Mathematica

Using the following list,

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

Is it possible to select lists where the second value is → 3. The desired result is lower

 {5, 6, 7, 8} 

setting up the following code that currently retrieves all values> 2 in the list

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

Sophisticated query solutions can be found here Conditional Data Manipulation in Mathematica

+4
source share
5 answers

Alternatively, using Select

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

Output

 {{5, 6, 7, 8}} 
+7
source

In this case, Select is the easiest method, but Pick can also be useful in related issues.

 list = {{a, b, c, d}, {1, 2, 3, 4}, {5, 6, 7, 8}}; Pick[list, #>3& /@ list[[All, 2]] ] 

To explain, Pick takes two lists (or nested lists) of the same form and returns each element from the first for which the corresponding element is second True . (It can also take a third argument to match for elements other than True .)

Here, the second column is retrieved using list[[All, 2]] , and then test #>3& displayed on each item. Then it is used as a selection list.


Responding to 500 comments requesting a generalization of the Select method:

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

This allows you to specify:

  • array : input array to extract from
  • index : column index to compare
  • value : value to compare with
  • range : Part specification for extracting from each row the result
+6
source

Comparison of speed of different solutions

Interestingly, Select always works faster with unpacked arrays, and for large arrays the difference is about an order of magnitude! Click the following table to enlarge:

Table

Code for time tests:

 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] 
+6
source

Syntax of alternative cases. The first element is skipped, the second is checked at> 3, and the rest of the list is ignored by us:

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

I doubt it will be faster than Select, but sometimes clearer, especially if the test includes different data types or corresponds to some substructure.

+4
source

EDIT:

As Alexey noted, the following constructions are more mathematical in Mathematica than my earlier solution.

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

and

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

One solution would be to use Cases

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

This is not useful if you want to (say) check if the 95th element is> 2. Thus, this is the best approach when you can easily specify the position:

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

All Articles