# Can I tell DeleteCases not to delete function arguments?

Given list = {1, 2, f[3, 4], {5, {6, g[7, h[8, 9]]}}, {f[10], 11}};

I want to get {f[3, 4], {{g[7, h[8, 9]]}}, {f[10]}}

just delete a single integer and need to keep the structure, use DeleteCases but get this result

DeleteCases[list, _Integer, All, Heads -> False]


{f[], {{g[h[]]}}, {f[]}}

Am I using it wrong, should I use a more suitable function?

list /. {expr : (f | g | h)[__] :> expr, _Integer -> Nothing}
(* {f[3, 4], {{g[7, h[8, 9]]}}, {f[10]}} *)

• A slight variation: list/.{_Integer:>Nothing,x:_f | _g | _h :> x} (and +1, of course) Commented Apr 10, 2023 at 18:31

You could use DeleteCases on each List:

MapAt[DeleteCases[_Integer], list, Drop[Position[list, List], 0, -1]]

{f[3, 4], {{g[7, h[8, 9]]}}, {f[10]}}


I might think of this as transforming each list into a special type of list that automatically deletes any non-atomic elements given to it.

list /. List -> Function[Null, Select[{##}, Not@*AtomQ]]


I generalized this to atoms instead of just integers, because that's what I "read between the lines" of your question. But of course you could stick with integers.

list /. List -> Function[Null, Select[{##}, Not@*IntegerQ]]


or

list /. List -> Function[Null, DeleteCases[{##}, _Integer]]

list //. {OrderlessPatternSequence[__Integer, keep : (_@__) ..]} :> {keep}

{f[3, 4], {{g[7, h[8, 9]]}}, {f[10]}}


And a variation on @xzczd's method:

list /. {keep : Except[List]@__ :> keep, _Integer -> Nothing}

{f[3, 4], {{g[7, h[8, 9]]}}, {f[10]}}

• Just keep___ works for the first (and three underscores/dots are needed if it's possible to empty a list)
– att
Commented Apr 11, 2023 at 7:36

Another way to do this using SubsetReplace, Internal-CopyListStructure and ReplaceAll:

InternalCopyListStructure[list,
SubsetReplace[Flatten@list, {_Integer} -> s]] /. s -> Nothing

(*{f[3, 4], {{g[7, h[8, 9]]}}, {f[10]}}*)


Or the equivalent form:

F = Activate@
InternalCopyListStructure[#,
SubsetReplace[Flatten@#, {_Integer} -> Inactive[Nothing]]] &;

F@list

(*{f[3, 4], {{g[7, h[8, 9]]}}, {f[10]}}*)


A generalization of @xzczd's answer is to find the heads of expressions that we don't want to remove using Cases as follows:

patt = Alternatives @@ Blank /@ Union@Cases[#,
s : Except[_List | _Integer] :> Head[s], {0, ∞}] &@list

(*_f | _g | _h*)

list /. {_Integer :> Nothing, s : patt :> s}

(*{f[3, 4], {{g[7, h[8, 9]]}}, {f[10]}}*)


Another way, using Cases and DeleteCases:

exc = Cases[#, s : Except[_List | _Integer] :> s, {0, ∞}] &;

DeleteCases[#, Alternatives @@ Complement[Flatten@#, exc@#], Depth@#] &@list

(*{f[3, 4], {{g[7, h[8, 9]]}}, {f[10]}}*)


I can't tell if this is clever or just silly, but it's a variation on the theme:

In[22]:= noIntegers[bef___, __Integer, aft___] := noIntegers[bef, aft];
In[23]:= list /. List -> noIntegers /. noIntegers -> List

Out[23]= {f[3, 4], {{g[7, h[8, 9]]}}, {f[10]}}

list = {1, 2, f[3, 4], {5, {6, g[7, h[8, 9]]}}, {f[10], 11}};


A variant of E. Chan-López solution:

p = Union @ Cases[list, a_[__] /; a =!= List :> a, -1] /.

list /. {s : p :> s, _Integer :> Nothing}