# Select applied to multiple objects

I have a matrix and want to extract rows according to some criterion. Then I have other matrices and want to extract the same rows. For example, if my criterion is to find rows where all the elements are smaller than some number, I can write

m = Table[i j/10., {i, 5}, {j, 3}]


which returns

{
{0.1, 0.2, 0.3},
{0.2, 0.4, 0.6},
{0.3, 0.6, 0.9},
{0.4, 0.8, 1.2},
{0.5, 1., 1.5}
}


Then

Select[m, Max[#] < 1. &]


selects the first three rows of m. Alternatively,

m[[{1, 2, 3}, All]]


also extracts the same first three rows. So if I had the list {1,2,3}, I could use that list to extract the corresponding rows from any number of other objects. To find the list, I tried

Position[m, Max[#] < 1. &]


but it returns the empty list. Why doesn't this work? Is there a better approach? Also, for my real application, execution speed is potentially important.

Update: I am impressed at how many different ways to do this exist! I was also interested in how fast the approaches run. I ran a test on a slightly different task (closer to my application, although my initial list isn't random!).

m = RandomReal[{-1, 1}, {1000, 20}];
lst1 = Position[(Max[Abs[#]] < 0.9) & /@ m, True] // Flatten //
AbsoluteTiming;
lst2 = ResourceFunction["SelectIndices"][m, (Max[Abs[#]] < 0.9) &] //
Flatten // AbsoluteTiming;
lst3 = Flatten@
Position[
Flatten[ResourceFunction[
"ThroughOperator"][{(Max[Abs[#]] < 0.9) &}] /@ m], True] //
AbsoluteTiming;
lst4 = ResourceFunction["SelectPositions"][m, (Max[Abs[#]] < 0.9) &] //
Flatten // AbsoluteTiming;
lst5 =
Position[m, _?(AllTrue[(Max[Abs[#]] < 0.9) &]), {1},
lst6 = Flatten[
Table[Position[m, Select[AllTrue[# < 1 &]][m][[i]]], {i, 1,
Length@Select[AllTrue[(Max[Abs[#]] < 0.9) &]][m]}]] //
AbsoluteTiming;
{lst1[[1]], lst2[[1]], lst3[[1]], lst4[[1]], lst5[[1]], lst6[[1]]}


returns

{0.002089, 0.002717, 0.003723, 0.007242, 0.009424, 1.09962}


Sorry for obsessing, but here's a new winner (replaces anon. function with explicit one):

(Position[LessThan[0.9] /@ (Max /@ Abs[m]), True] // Flatten //
AbsoluteTiming)[[1]]


returns 0.001294. By the way, if the number of rows is smaller than 1000, the ordering of which is fastest changes. (Try 100 and 10.) But method 1 and this variant seem always to be the fastest.

• Might want to use ResourceFunction["SelectPositions"] or ResourceFunction["SelectIndices"] to get the locations of interest, then use those in Part or Extract. Commented Feb 5, 2023 at 1:12

lst = Position[(Max[#]<1)&/@m,True]

(* {{1}, {2}, {3}} *)


Using Extract

 Extract[m,lst]
(* {
{0.1, 0.2, 0.3},
{0.2, 0.4, 0.6},
{0.3, 0.6, 0.9}
} *)



Using Part

 m[[Flatten@lst]]

(* {
{0.1, 0.2, 0.3},
{0.2, 0.4, 0.6},
{0.3, 0.6, 0.9}
} *)


And:

m//#[[Flatten@Position[(Max[#]<1)&/@m,False]]]&

(* {
{0.4, 0.8, 1.2},
{0.5, 1., 1.5}
} *)

• This was the most useful to me (and runs very fast). Thanks! It's also a good reminder to me to look at the Function Repository. I will check out those other functions, too. Commented Feb 5, 2023 at 15:33

My suggested solution is based on

So if I had the list {1,2,3}, I could use that list to extract the corresponding rows from any number of other objects. To find the list, I tried I tried Position[m, Max[#] < 1. &] but it returns the empty list.

I will borrow something from @Syed's answer. Observe that while

Position[m, Select[AllTrue[# < 1 &]][m]]


does not give you anything, the following

Position[m, Select[AllTrue[# < 1 &]][m][[1]]]


gives

Wrap a nice Table around it and Flatten it

Flatten[Table[
Position[m, Select[AllTrue[# < 1 &]][m][[i]]], {i, 1,
Length@Select[AllTrue[# < 1 &]][m]}]]


Edit another way to get the {1,2,3} is to use the resource function called ThroughOperator that can do that. This is a development thanks to @Sjoerd Smit.

Flatten@Position[
Flatten[ResourceFunction["ThroughOperator"][{Max[#] < 1 &}] /@ m],
True]


Using Select:

m = Table[i j/10., {i, 5}, {j, 3}]
Select[AllTrue[# < 1 &]][m]


Using Pick:

Define a helper function:

f[k_List] := Max[k] < 1
Pick[m, f /@ m]


Using DeleteCases:

DeleteCases[m, _?(AnyTrue[# > 1 &])]


Using Position/Extract:

As Position expects a pattern:

pos = Position[m, _?(Max@# < 1 &), {1}]


OR

pos = Position[m, _?(AllTrue[# < 1 &]), {1}, Heads -> False]


give you the positions that you can extract values from other matrices; e.g.,

Extract[m, pos]


Result:

{{0.1, 0.2, 0.3}, {0.2, 0.4, 0.6}, {0.3, 0.6, 0.9}}

• The only issue here is that, without an index (such as lst), I do not see how to extract the columns from multiple matrices. If I had only one matrix to extract from, these would be fine. Commented Feb 5, 2023 at 15:34
• Thanks, I didn't read the question carefully enough, it seems. I have updated the answer that uses a pattern for extracting the said positions..
– Syed
Commented Feb 5, 2023 at 16:21

Using GroupBy and Lookup:

Lookup[GroupBy[m, Max@# < 1 &], True]
(*{{0.1, 0.2, 0.3}, {0.2, 0.4, 0.6}, {0.3, 0.6, 0.9}}*)
Lookup[GroupBy[m, Max@# < 1 &], False]
(*{{0.4, 0.8, 1.2}, {0.5, 1., 1.5}}*)

m = Table[i j/10., {i, 5}, {j, 3}];


Using ReplaceAt (new in 13.1)

ReplaceAt[m, _ :> Nothing, Position[m, x_ /; Max[x] >= 1, 1]]


Using SequenceSplit (new in 11.3)

Catenate @ SequenceSplit[m, {x_} /; Max[x] > 1]


Using Cases

Cases[m, x_ /; Max[x] <= 1]


All return

{{0.1, 0.2, 0.3}, {0.2, 0.4, 0.6}, {0.3, 0.6, 0.9}}