18
$\begingroup$

Suppose I have a few symbols, one of which has a value:

{abc1, abc2 = 5, abc3};

I can use Names to get the list of names, as strings:

InputForm[names = Names["Global`abc*"]]
(* {"abc1", "abc2", "abc3"} *)

Now I want to find which symbols have values. This fails, because ValueQ expects the first argument to be a Symbol, not a String:

Select[names, ValueQ]
(* {} *)

This fails (with lots of messages), because ValueQ doesn't evaluate the argument enough:

Cases[names, st_ /; ValueQ[Symbol[st]]]
(* {"abc1", "abc2", "abc3"} *)

If we force evaluation, we go too far, and this fails because we get ValueQ[5] instead of ValueQ[abc2]:

Cases[names, st_ /; ValueQ[Evaluate[Symbol[st]]]]
(* {} *)

This approach works, but is far from elegant:

Cases[names, st_ /; ToExpression["ValueQ[" <> st <> "]"]]
(* "abc2" *)
$\endgroup$

3 Answers 3

24
$\begingroup$

I usually use

ToExpression["symbol",  InputForm, ValueQ]

ToExpression will wrap the result in its 3rd argument before evaluating it.


Generally, all functions that extract parts (Extract, Level, etc.) have such an argument. This is useful when extracting parts of held expressions. ToExpression acts on strings or boxes, but both the problem with evaluation control and the solution is the same. I thought this was worth mentioning here.

$\endgroup$
3
  • 2
    $\begingroup$ Note that ValueQ is not innocent - it leaks evaluation. Here is some discussion, where I also contributed an answer with what is supposed to be a safer version of valueQ based on one-step evaluation: stackoverflow.com/questions/4599241/…. It is overly complex, I know it can be written better, but the point is to be wary of the system ValueQ, to avoid nasty surprises. $\endgroup$ Jan 18, 2012 at 20:55
  • 1
    $\begingroup$ @Leonid I think ValueQ is safe for as long as it's acting on a symbol only (i.e. is looking at OwnValues), but it evaluates the argument for anything else. Is this correct? I remember I looked at the implementation of ValueQ once (it's accessible) and concluded this, but that was a long time ago. $\endgroup$
    – Szabolcs
    Jan 18, 2012 at 21:14
  • 1
    $\begingroup$ Yes, I think I came to the same conclusions. Actually, in the linked SO discussion, I give some explicit example where it leaks evaluation. Can not dig in deeper now, need to get some sleep :). But for OwnValues only, there is a bullet-proof solution: (HoldComplete[sym]/.OwnValues[sym])=!=HoldComplete[sym] - very simple and robust. $\endgroup$ Jan 18, 2012 at 21:25
9
$\begingroup$

You can also use MakeExpression

ValueQ @@ MakeExpression["abc2"]
$\endgroup$
2
$\begingroup$

This one is a different method to access symbol names and values (I think it originates from MathGroup):

(edited to fit the original question)

Attributes[symbolToRule] = {HoldAll, Listable};
symbolToRule[sym_String] := HoldForm[sym] -> Head[Symbol[sym]] =!= Symbol;
symbolToRule[sym_Symbol] := HoldForm[sym] -> ValueQ[sym];

with symbols:

{a, b = 5, c};
rules = symbolToRule[{a, b, c}]
Pick[First /@ rules, Last /@ rules]

output:

Mathematica graphics

with strings:

rules = symbolToRule[{"a", "b", "c"}]
Pick[First /@ rules, Last /@ rules]

output:

Mathematica graphics

$\endgroup$
3
  • $\begingroup$ Ah, but you're using {a,b,c} instead of {"a","b","c"}. That's the tricky part... :-) $\endgroup$ Jan 18, 2012 at 21:08
  • $\begingroup$ Ah, I see. Trying to cover this up cleverly... $\endgroup$ Jan 18, 2012 at 21:14
  • $\begingroup$ @IstvánZachar pretty neat approach. +1 ! $\endgroup$
    – Ali Hashmi
    Feb 5, 2017 at 12:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.