Extract variables from sum of unevaluted functions

I have sums of the form

sum = a f[1,1,0] + b f[1,2,0] + c f[1,2,1] + ...

It is always linear in f[a,b,c]. I would like a function that returns a list of all f[a,b,c] appearing in the sum. Following an answer from this question, I have created the following function, which behaves correctly when evaluated on sum:

getVariables[expr_, f_] := DeleteDuplicates@Cases[expr,f, Infinity];
getVariables[sum, f[_,_,_]]
(*{f[1, 1, 0], f[1, 2, 0], f[1, 2, 1], ...}*)

The problem is that when there's a single function it does not work:

getVariables[f[a,b,c], f[_,_,_]]
(* {} *)

It only fails when it's exactly f[a,b,c] and works fine for e.g. 2f[a,b,c].

What am I missing here? I do not get why it would fail in that case.

• The level specification Infinity (which is equivalent to {1, Infinity} does not include level 0 (i.e. the whole expression), which is why nothing is found in f[a,b,c]. You can use {0, Infinity} or All instead to also include level 0 Oct 13 '19 at 15:19

Expanding on @Lukas Lang's comment, the problem comes from the default level specification of Cases and the fact that f appears as the head (or rather, at part 0/only in level 0) in f[a,b,c].

From the Cases documentation

The default value for levelspec in Cases is {1}.

So when a level is specified, say for example as Cases[f[a, b, c], _f, Infinity], Mathematica implicitly interprets this is Cases[f[a, b, c], _f, {1, Infinity}]. This works great for expressions like your sum since it has the form

a f[1, 1, 0] + b f[1, 2, 0] + c f[1, 2, 1] // FullForm
Level[%, {1}]

Plus[Times[a, f[1, 1, 0]], Times[b, f[1, 2, 0]], Times[c, f[1, 2, 1]]]

{a f[1, 1, 0], b f[1, 2, 0], c f[1, 2, 1]}

and the stuff you want to work with starts at level 1.

Now with that being said, just the single instance of f[a, b, c] has a different structure and its elements on level 1 are

Level[f[a, b, c], {1}]

{a, b, c}

So when the above usage of Cases (i.e. starting at level 1) is called on this structure, it doesn't see the f, and thus doesn't return anything.