18

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" *)
J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
Brett Champion
  • 20,779
  • 2
  • 64
  • 121

3 Answers3

24

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.

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
  • 2
    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: http://stackoverflow.com/questions/4599241/checking-if-a-symbol-is-defined/4621562#4621562. 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. – Leonid Shifrin Jan 18 '12 at 20:55
  • 1
    @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. – Szabolcs Jan 18 '12 at 21:14
  • 1
    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. – Leonid Shifrin Jan 18 '12 at 21:25
9

You can also use MakeExpression

ValueQ @@ MakeExpression["abc2"]
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
2

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

István Zachar
  • 47,032
  • 20
  • 143
  • 291