3

Consider an expression exp = a^2 + b + c which has variables a, b, and c, and its values are stored in aval = 1, bval = 2, and cval = 3.

If cval is not given I would like the expression to get evaluated to 3 + c.

The function I have written is:

rulesVal[exp_] := 
 Cases[Variables@exp, 
  x_ /; Head[x] == Symbol :> (x -> Symbol[ToString[x] <> "val"])]

toVal[exp_] := exp /. rulesVal[exp]

When I input a^2 + b + c to toVal function, I get 3 + cval.

How do I get 3 + c?

corey979
  • 23,947
  • 7
  • 58
  • 101
Anjan Kumar
  • 4,979
  • 1
  • 15
  • 28
  • 2
    Have you seen ValueQ? – Michael E2 Dec 13 '16 at 01:44
  • 3
    The typical way this is written in MMA is exp=a^2+b+c and exp/.{a->1,b->2} which yields 3+c – Manuel --Moe-- G Dec 13 '16 at 01:46
  • @ Manuel, I know that. That is good enough for a small expression. However, when it contains so many variables in an expression, it becomes difficult to see which variables are in the expression, and correspondingly writing a rule for that variable. – Anjan Kumar Dec 13 '16 at 02:15
  • 2
    BTW, did you generate the assignments aval = 1 etc., or are they given to you in a data file or something? I ask because there are better ways to manage such data. val[x_] := x and then val[a] = 1; val[b] = 2; usage something like exp /. Thread[# -> val /@ #]&@Variables[exp]. Or similarly with Association. – Michael E2 Dec 13 '16 at 02:21
  • @ Michael E2, I tried using ValueQ in the following way, rulesVal[exp_] := If[ValueQ[ Symbol[ToString[#] <> "val"]], (# -> Symbol[ToString[#] <> "val"]), # -> #] & /@ (Variables@exp);

    toVal[exp_] := exp /. rulesVal[exp];

    When evaluating toVal[exp], it gives an error which says "OwnValues::sym: Argument Symbol[ToString[a]<>val] at position 1 is expected to be a symbol."

    – Anjan Kumar Dec 13 '16 at 02:22
  • @MichaelE2, thank you. I like the simple way you proposed.
    I wrote those assignments and there are around 50 of such assignments. If there is no other way, then I will adapt your way.
    – Anjan Kumar Dec 13 '16 at 02:27
  • 1
    Yes, I reckon ValuesQ is perhaps not so easy because it is HoldAll: it's tricky to pass it the unevaluated symbol. If the assignments are all numeric values, try NumericQ. – Michael E2 Dec 13 '16 at 02:32
  • @MichaelE2, it works with NumericQ. Thanks a lot. – Anjan Kumar Dec 13 '16 at 02:35
  • I suppose you can answer your own question, then? (It is quite ok. You may still get better answers from others.) – Michael E2 Dec 13 '16 at 02:37

1 Answers1

6

Direct solution

aval = 1;
bval = 2;
cval =.;

exp = a^2 + b + c;

rule =
 s_Symbol :>
  With[{sv = ToHeldExpression[ToString[s] <> "val"]},
    ReleaseHold[sv] /; ValueQ @@ sv
  ];

exp /. rule
3 + c

Reference:

Recommended alternative

However this (the method above) really is a poor way to approach this problem in my opinion.

It should not really be difficult to make a Rule list (as proposed by Manuel --Moe-- G). If you use an Association it is even easier:

asc = <||>;
asc[a] = 1;
asc[b] = 2;

exp = a^2 + b + c;

exp /. asc
3 + c

If you are using an older version of Mathematica that does not have Associations then a DownValues definition (indexed object) as Michael proposed is a good alternative:

val[a] = 1;
val[b] = 2;

exp = a^2 + b + c;

exp /. s_Symbol /; ValueQ[val[s]] :> val[s]
3 + c
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371