6

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?

yode
  • 26,686
  • 4
  • 62
  • 167

5 Answers5

4
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?

Kuba
  • 136,707
  • 13
  • 279
  • 740
2
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

yode
  • 26,686
  • 4
  • 62
  • 167
2
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]]&]
Mike Honeychurch
  • 37,541
  • 3
  • 85
  • 158
2

you can use Complement instead of Union

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

(* {c -> 2, a -> 8, b -> 2} *)
Ali Hashmi
  • 8,950
  • 4
  • 22
  • 42
1

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.

C. E.
  • 70,533
  • 6
  • 140
  • 264