# Select/Delete with Sublist elements?

Probably easy and short question, I still didn't fully figure out how to easily select/delete sublists from a list. Example:

tt = {{2, 4}, {4, 8}};


I want to delete/select all the elements where the difference between them (Abs) is greater than four.

I would use either

Cases[data, {x_, y_} /; Abs[x - y] > 4]


or

With[{diff = Abs[data[[All, 1]] - data[[All, 2]]] - 4},
Pick[data, UnitStep[diff]*Unitize[diff], 1]
]


The first clearly demonstrates what you are trying to do, the second is much faster...

data = RandomInteger[{0, 100}, {10^6, 2}];

(m1 =  Cases[data, {x_, y_} /; Abs[x - y] > 4]); // AbsoluteTiming

==> {2.8393092, Null}

(m2 =
With[{diff = Abs[data[[All, 1]] - data[[All, 2]]] - 4},
Pick[data,UnitStep[diff]*Unitize[diff], 1]]); // AbsoluteTiming

==> {0.1248024, Null}

m1 == m2

==> True


Assuming you are working with random data and don't expect equality, the second method can be simplified to...

Pick[data, UnitStep[Abs[data[[All, 1]] - data[[All, 2]]] - 4], 1]


Edit:

Of course if you want to delete elements where Abs[x-y] > 4 you can modify the Cases definition as

Cases[data, {x_, y_} /; Abs[x - y] <= 4]


And the Pick method by swapping out the 1 in the last argument with 0.

• Since UnitStep==1, you could use Pick[data, UnitStep[4 - Abs[data[[All, 1]] - data[[All, 2]]]], 0] if you want the absolute value to be strictly larger than 4. – Heike Mar 1 '12 at 17:27

You can select all sublists the elements of which differ by more than 3 as follows:

Select[tt, Abs[#[] - #[]] > 3 &]
(*{{4, 8}}*)


or using conditional patterns:

Cases[tt, x_ /; Abs[x[] - x[]] > 3]


(and you can delete them by either selecting those Not satisfying the condition, or using DeleteCases).

You could also do

Scan[If[Abs[#[] - #[]] > 3, Sow[#]] &, tt] // Reap //
Last // Last


or even

MapThread[If[Abs[#1 - #2] > 3, Sow[{#1, #2}]] &, Transpose@tt]; //
Reap // Last // Last


Finally using Compile and InternalBag, as described by Andy here, you can do

cs = Compile[{{lst, _Integer, 2}},
Module[{bag = InternalBag[], l = Length@lst},
Do[
If[
Abs[lst[[i, 1]] - lst[[i, 2]]] > 3.,
InternalStuffBag[
bag,
lst[[i]], 1
]
],
{i, l}
];
Partition[InternalBagPart[bag, All], 2]],
CompilationTarget -> "C",
RuntimeOptions -> "Speed"
];


which is roughly as fast as the Pick approach described in another answer (neither unpacks).

Cases[tt, {a_, b_} /; Abs[a - b] >= 4]

 {{4, 8}}


or

DeleteCases[tt, {a_, b_} /; Abs[a - b] < 4]

 {{4, 8}}


The latter approach could be better if pairs Abs[a-b] > 4 are generic.

I would also choose Pick for speed, but I would formulate it a little differently:

Pick[
tt,
UnitStep[Abs[# - #2] & @@ Transpose[tt] - 5],
1
]


To pick the complement change the third argument from 1 to 0.

Although not as fast as Pick, another possibility is to use GatherBy which allows selecting/deleting subsets of data based on a condition:

  data = {{2, 4}, {4, 8}, {5, 9}, {1, 3}};
{deleted,selected}= GatherBy[data, UnitStep[Abs[#[] - #[]] - 4] &]


returns:

   {{{2, 4}, {1, 3}}, {{4, 8}, {5, 9}}}

• GroupBy is a useful alternative to GatherBy, since the result is more obvious to interpret. – Sjoerd Smit Dec 14 '17 at 10:49