8
$\begingroup$

How do I change the value of a rule? For example, If I have a = x->3, how do I reset the value of x/.a to 4, so that x/.a returns 4?

The context of this question is, I have a list of replacement rules, ex. list = {"name1"->1, "name2"->2, "name3"->3}. I am hoping to change values of these rules without having to know the orders of the list. Right now I am accessing values of rules using "name1"/.list, but I do not know a good way of changing the values

$\endgroup$
1
  • 2
    $\begingroup$ a = x -> 4? a[[-1]] = 4? Your question is clear enough as it is, but it would probably help (to get a better answer, rather than having the question closed) if you gave some context for this--what are you actually trying to achieve? $\endgroup$ Feb 5 '15 at 0:01
3
$\begingroup$

This embarrassingly simple approach also works.

list = {"name1" -> 1, "name2" -> 2, "name3" -> 3};
list /. Rule["name2", 2] -> Rule["name2", 4]

which produces {"name1" -> 1, "name2" -> 4, "name3" -> 3}

$\endgroup$
5
$\begingroup$

Try also this:

 list = {"name1" -> 1, "name2" -> 2, "name3" -> 3};

list /. ("name1" -> x_) -> ("name1" -> a)

(* {"name1" -> a, "name2" -> 2, "name3" -> 3}  *)

Another way would be to use associations as it has been already mentioned by Nasser above. The Associations have a very simple way to change a value for a given key: an[key]=val, where an is an association yields the association, in which after the operations the key obtains a new value val.

This may be summarized in the function below. In this function the list of rules is transformed into the association, the value of the key is changed, and the association is transformed back into the list of rules.

Its arguments are: nameis the name in your list whose value you need to replace, valueis the new value for this name and ruleis the list of rules where you need to replace a value:

 replInRule[name_String, rule_List, value_] := Module[{an},
  an = Association[rule];
  an[name] = value;
  Normal[an]
  ]

which acts as follows:

    replInRule["name1", list, a]

(* {"name1" -> a, "name2" -> 2, "name3" -> 3} *)

Have fun!

$\endgroup$
3
$\begingroup$

I have a list of replacement rules, ex. list = {"name1"->1, "name2"->2, "name3"->3}. I am hoping to change values of these rules without having to know the orders of the list.

Why not use Association?

myRules = <|"name1" -> 1, "name2" -> 2|>;
list = {"name1", "name2", "name3"};
list /. myRules

Mathematica graphics

Now you can change a rule without knowing the order.

myRules["name1"] = 99;
list /. myRules

Mathematica graphics

myRules

Mathematica graphics

You can also always get a normal looking rules out of the Association using Normal if needed, like this:

 Normal[myRules]

Mathematica graphics

$\endgroup$
2
  • 1
    $\begingroup$ I am trying to deploy the program to CDF 9, so Association is not avaiblible. But looks like Association provides an elegant way to achieve what I want, I'd definitely try it in the future $\endgroup$
    – Yituo
    Feb 5 '15 at 14:15
  • $\begingroup$ @Yituo Association is new in 10. CDF only supports 9. But if you wait few days, CDF 10 is supposed to be out. Please see Roadmap for CDF look at the bottom, post by Andre Kuzniarek, 9 days ago. He said it will be out in 2 weeks. So only few more days and it should be out, lets hope. $\endgroup$
    – Nasser
    Feb 5 '15 at 14:18
2
$\begingroup$
list = {"name1" -> 1, "name2" -> 2, "name3" -> 3};

rrF1 = # /. HoldPattern[#2 -> _] :> (#2 -> #3) &;
rrF1[list, "name2", 4]
(* {"name1" -> 1, "name2" -> 4, "name3" -> 3} *)

Or

rrF2 = ReplacePart[#, {1, -1} Position[#, #2][[1]] -> #3] &;
rrF2[list, "name1", 5]
(* {"name1" -> 5, "name2" -> 2, "name3" -> 3} *)
$\endgroup$
0
$\begingroup$

If you are using a version of Mathematica that predates Association but you want better performance in update operations than you will get from directly manipulating a list of Rule expressions consider using DownValues.

Here is an example. I build a large list of Rules and an equivalent series of definitions to defs:

SeedRandom[0]
rules = Rule @@@ RandomInteger[1*^7, {1*^6, 2}];
(defs[#] = #2) & @@@ rules;

The time to replace a single rule is considerable:

rules /. (5399164 -> _) -> (5399164 -> "new") // AbsoluteTiming // First
0.860049

The time to update one of the DownValues of defs is minor:

(defs[5399164] = "new") // AbsoluteTiming // First
0.  (* below floor of measurement *)

But perhaps you cannot use defs directly. For example if you are operating upon a held expression Map will not evaluate in the desired way. There is a "trick" you might use:

asRules[s_Symbol] :=
  x_ :> With[{v = s @ Unevaluated @ x]}, v /; Head[v] =!= s]

An example of its use. First a new defs with rules as in your question:

ClearAll[defs]

(defs[#] = #2) & @@@
  {"name1" -> 1, "name2" -> 2, "name3" -> 3};

defs["name2"] = 4;

Now a replacement operation upon a held expression containing Print:

Hold["name1", 7 + 7 + "name2", Print["Fail!"]*"name3"] /. asRules[defs]
Hold[1, 7 + 7 + 4, Print["Fail!"] 3]

Note that none of the expressions evaluated inappropriately yet the replacements were made.

This introduces significant overhead for a replacement operation so you must weight this against the speed of updating (replacing) rules. If you have many rules and the LeafCount of the LHS of your replacement operations is low this method should serve you well. If however you have few rules and the LHS of your replacements is large you would do better to use a plain list of Rules.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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