Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Lets say I have a list of patterns

p={
  HoldPattern[f[x___]] :> {x},
  HoldPattern[f[a_,b_]] :> {a,b},
  HoldPattern[f[a_,a_]] :> {a,a},
  HoldPattern[f[x_]] :>x
} 

what is the most elegant way to add another pattern to the list while removing all duplicates? For example let's say I what to add f[c_,d_]:>code then f[a_,b_] should be mapped as a duplicate but not f[a_,a_].

share|improve this question
1  
Have you seen How to match, unify and merge patterns? –  Kuba Aug 22 '13 at 18:11
    
@Kuba No. This might be a duplicate. Let me read. –  Liam William Aug 22 '13 at 18:15
    
I take it you want to match only the LHS of the rules; is that correct? I will extend my answer with an example once confirmed. –  Mr.Wizard Aug 22 '13 at 18:15
    
@Mr.Wizard Yes that is correct, but I do not want to keep adding duplicates (although precedence does work). –  Liam William Aug 22 '13 at 18:15

1 Answer 1

up vote 5 down vote accepted

Automatic behaviors

It's worth noting that replacement rules have precedence by order, therefore you may not need to remove the duplicates. For example:

Prepend[p, HoldPattern[f[c_, d_]] :> foo[c, d]];

f[1, 2] /. %
foo[1, 2]

For the specific rules you show and for matching of the left-hand-side only you can use the automatic duplicate removal of definitions made with Set or SetDelayed:

Cases[p, (_[lhs_] :> rhs_) :> (lhs := rhs)];

f[c_, d_] := foo[c, d]

DownValues[f]
{HoldPattern[f[a_, a_]] :> {a, a}, HoldPattern[f[c_, d_]] :> foo[c, d], 
 HoldPattern[f[x_]] :> x, HoldPattern[f[x___]] :> {x}}

If the sorting that occurs here is undesired that can be temporarily disabled with SetSystemOptions["DefinitionsReordering" -> "None"] as I did for How to select minimal subsets?

Manual filtering

A manual approach for matching the LHS of arbitrary rules is to replace all Pattern names with indexes before comparing:

uniform[(lhs_ -> _) | (lhs_ :> _)] :=
 lhs /. MapIndexed[
   Verbatim[Pattern][#, x_] :> Pattern[#2, x] &,
   Cases[lhs, Verbatim[Pattern][name_, _] :> HoldPattern[name], -1] // DeleteDuplicates
  ]

p2 = Prepend[p, HoldPattern[f[c_, d_]] :> foo[c, d]];

First /@ GatherBy[p2, uniform]
{HoldPattern[f[c_, d_]] :> foo[c, d], HoldPattern[f[x___]] :> {x}, 
 HoldPattern[f[a_, a_]] :> {a, a}, HoldPattern[f[x_]] :> x}

Other approaches

If the methods above are not sufficient you may be facing a complicated problem; see:
How to generally match, unify and merge patterns?

From Oleksandr's answer there we learn of Internal`ComparePatterns which may be used for the automatic definition filtering illustrated in section one. If one is comfortable with using undocumented internal functions one might use:

ptest[(L1_ -> _) | (L1_ :> _), (L2_ -> _) | (L2_ :> _)] :=
  Internal`ComparePatterns[L1, L2] === "Identical"

p2 = Prepend[p, HoldPattern[f[c_, d_]] :> foo[c, d]];

DeleteDuplicates[p2, ptest]
{HoldPattern[f[c_, d_]] :> foo[c, d], HoldPattern[f[x___]] :> {x}, 
 HoldPattern[f[a_, a_]] :> {a, a}, HoldPattern[f[x_]] :> x}

For matching both the LHS and RHS of rules you can try the method I provided for:
Pattern matching a pattern with patterns.

share|improve this answer
    
Something of the form StringMatchQ[Internal`ComparePatterns[f[a_, b_], f[a_,a_]], "Equivalent" | "Identical"] would work(from what I understand now), but I'm not certain if I can just use Union and SameTest for filtering out the options because I don't really know if there is a guarantee in which order Union works. –  Liam William Aug 22 '13 at 19:03
    
@Liam yes, I intended to add that. I'm back to working on this answer now. –  Mr.Wizard Aug 22 '13 at 19:39

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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