# Extract all instances of variables matching a pattern?

There is a very convenient function Dt that allows to take a total differential of any expression, e.g.:

expr = (a + b c)/d;
Dt[expr]


(Dt[a] + c Dt[b] + b Dt[c])/d - ((a + b c) Dt[d])/d^2

Consider a case where expr is generic (it is not known a priori which and how many variables appear). I would like to have a function that extracts a list of all Dt[x_] from an expression. For the above example it should do:

extract[Dt[expr]]


{Dt[a],Dt[b],Dt[c],Dt[d]}

My own version of this function is:

extract[x_] := Select[Variables[x], (Head[#] === Dt) &]


but I feel like extracting all variables and then selecting a subset is too hacky. Is there a nice way to implement this?

EDIT

Bob Hanlon and Mr. Wizard suggested to use Cases and Union. Unfortunately, these functions appear to be slower than the above in some cases:

Select[Variables[ Dt[(a + b c)/d + (a + b c)/d q]], (Head[#] === Dt) &] // AbsoluteTiming


{0.0000811731, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q]}}

compared to

Cases[Dt[(a + b c)/d + (a + b c)/d q], _Dt, {-2}] // Union // AbsoluteTiming


{0.000136221, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q]}}

• Cases[Dt[expr], _Dt, Infinity] // Union May 22, 2017 at 21:37
• @BobHanlon Or slightly shorter: Cases[Dt[expr], _Dt, {-2}] // Union -- the single level search should be somewhat faster with large expressions as well. May 22, 2017 at 21:38
• @Mr.Wizard BobHanlon Thank you for the suggestions! Unfortunately that does not yield a speed up. See the edit of my question. May 22, 2017 at 21:45
• Union@Cases[expr, HoldPattern[Dt[_]], Infinity] May 22, 2017 at 21:50

Of the various methods proposed in comments, plus a hybrid, I find my proposal fastest:

foo = Dt[(a + b c)/d + (a + b c)/d q + ((a + b c)/d + (a + b c)/d q)/z +
q r ((a + b c)/d + (a + b c)/d q + ((a + b c)/d + (a + b c)/d q)/z)];

Select[Variables @ foo, (Head[#] === Dt) &]      // RepeatedTiming

Cases[foo, _Dt, Infinity] // Union               // RepeatedTiming

foo // Variables // Cases[_Dt]                   // RepeatedTiming

Union@Cases[foo, HoldPattern[Dt[_]], Infinity]   // RepeatedTiming

Cases[foo, _Dt, {-2}] // Union                   // RepeatedTiming

{0.0000269, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q], Dt[r], Dt[z]}}

{0.00002049, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q], Dt[r], Dt[z]}}

{0.000019798, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q], Dt[r], Dt[z]}}

{0.00001882, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q], Dt[r], Dt[z]}}

{0.0000145, {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q], Dt[r], Dt[z]}}

• Guess, I was not using the correct timing function. Sorry about that! May 22, 2017 at 22:02
• Wouldn't the results be more accurate if you precede each line with ClearSystemCache[];? May 23, 2017 at 0:08
• @BobHanlon I don't see why that would be needed in this case, and using it doesn't appear to change the result. Were we using something like Simplify I think it would be another story. May 23, 2017 at 9:08
• On my system (Mac) I got a slightly different ordering using it. May 23, 2017 at 13:00
foo =
Dt[(a + b c)/d + (a + b c)/d q + ((a + b c)/d + (a + b c)/d q)/z +
q r ((a + b c)/d + (a + b c)/d q + ((a + b c)/d + (a + b c)/d q)/
z)];

Union@Level[foo, {-2}] // Cases[#, _Dt] &
(* {Dt[a], Dt[b], Dt[c], Dt[d], Dt[q], Dt[r], Dt[z]} *)


or

Select[Union@Level[expr, {-2}], (Head@# === Dt)&]