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

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.