6
$\begingroup$

If I have a rule

oldRule = {a -> 1, b -> 2}

{a->1,b->2}

Then I have a new rule newRule = {a -> 8, c -> 2}.How to use it to update my oldRule?I hope to get

{a->8,b->2,c->2}

Actually I think the Union can implement this target.But it always will choice that small element.I don't know how to control this behavior.

Union[{a -> 8, c -> 2}, oldRule, SameTest -> (SameQ @@ Keys[{##}] &)]

{a -> 1, b -> 2, c -> 2}

Or any elegant workaround can do this?

$\endgroup$
6
  • $\begingroup$ Are Associations allowed? $\endgroup$
    – Kuba
    May 7, 2017 at 6:52
  • $\begingroup$ @Kuba Do you mean <|a -> 1, b -> 2, c -> 2|>?It's allowed. $\endgroup$
    – yode
    May 7, 2017 at 6:58
  • $\begingroup$ @yode If you define the rules as associations, Join[oldRule, newRule] works. $\endgroup$ May 7, 2017 at 7:19
  • $\begingroup$ Related: 5970 $\endgroup$
    – C. E.
    May 7, 2017 at 7:28
  • $\begingroup$ Here is a general topic about associations: How to organically merge nested associations? $\endgroup$
    – Kuba
    May 7, 2017 at 7:47

5 Answers 5

4
$\begingroup$
foo = Normal@*Merge[Last]
foo@{oldRule, newRule}

Even this will do:

Normal @ <|oldRule, newRule|>

here is a link about nested associations:

How to organically merge nested associations?

$\endgroup$
2
$\begingroup$
Join[newRule,oldRule]

is all you need to ensure that the new rules are used because the first rule is only ever used. If you wanted to eliminate redundant rules then

DeleteDuplicatesBy[Join[newRule, oldRule], #[[1]]&]
$\endgroup$
2
$\begingroup$
DeleteDuplicatesBy[Join[newRule, oldRule], First]

{a->8,c->2,b->2}

Or by Anjan Kumar's comment

Normal[Join[<|oldRule|>, <|newRule|>]]

{a->8,b->2,c->2}

As my test,the solution based on Associations have a better performance

oldRule = Rule @@@ RandomInteger[1000, {200000, 2}];
newRule = Rule @@@ RandomInteger[1000, {200000, 2}];
AbsoluteTiming[Normal[Join[<|oldRule|>, <|newRule|>]];]
AbsoluteTiming[DeleteDuplicatesBy[Join[newRule, oldRule], First];]

Mathematica graphics

$\endgroup$
2
$\begingroup$

you can use Complement instead of Union

(#2~Join~Complement[#1, #2, SameTest -> (SameQ @@ Keys[{##}] &)]) &[oldRule, newRule]

(* {c -> 2, a -> 8, b -> 2} *)
$\endgroup$
1
$\begingroup$

This question has been answered by Rojo, in this answer:

changeRuleV4[rules : (_ -> _) ..] := 
 Join[FilterRules[#, Except@Alternatives[rules][[All, 1]]], {rules}] &

changeRuleV4[Sequence @@ newRule][oldRule]

{b -> 2, a -> 8, c -> 2}

We can also apply his other functions, which were written for the replacement of a single rule, repeatedly:

changeRule[rules_, rule : (sym_ -> _)] := 
 Append[FilterRules[rules, Except[sym]], rule]

changeRules[rules_, new_] := Fold[changeRule, rules, new]

changeRules[oldRule, newRule]

{b -> 2, a -> 8, c -> 2}

These solutions are slow, especially the second one, but I wanted to show the relation between this post and that other Q&A.

$\endgroup$

Your Answer

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

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