2
$\begingroup$

So I have this replacement rule that tends to work in most cases, except occasionally in cases like this:

p[{3, 4}] p[{5, 6}] p[{1, 4, 6}] p[{2, 3, 5}] //. 
  {p[list1_] p[list2_] :> 
    If[Length[Intersection[list1, list2]] != 0, p[Union[list1, list2]]]}

the problem seems to be that every time it evaluates the replacement rule, it only looks at the first two terms. If there's no replacement to be done it then just doesn't do anything. Does anybody know a way to maybe "scramble" the terms in the list or make the replacement look at every part of the expression?

$\endgroup$
5
  • $\begingroup$ You need a case when If evaluates to False, probably p[{3, 4}] p[{5, 6}] p[{1, 4, 6}] p[{2, 3, 5}] //. {p[list1_] p[list2_] -> If[Length[Intersection[list1, list2]] != 0, p[Union[list1, list2]], p[list1] p[list2]]} ? $\endgroup$
    – rhermans
    Nov 6, 2015 at 0:53
  • $\begingroup$ @rhermans I tried that, it doesn't make a difference. $\endgroup$ Nov 6, 2015 at 1:06
  • 2
    $\begingroup$ Please use a title that describes your problem!!! $\endgroup$ Nov 6, 2015 at 1:10
  • 1
    $\begingroup$ Do you only want to merge the lists from neighbouring elements of the product or any pair of elements of the product? (@belisariusisforth is right that Orderless is going to make "neighbouring" somewhat slippery.) Consider p[{1,2}] p[{2,3}] p[{4}] p[{5,6}] p[{6,1}] . $\endgroup$ Nov 6, 2015 at 1:23
  • $\begingroup$ Any pair of elements. So for your example the output would ideally be p[{1,2,3,5,6}] p[{4}] $\endgroup$ Nov 6, 2015 at 1:34

2 Answers 2

4
$\begingroup$

One way to do it is to make sure you allow for other terms that aren't part of the match, like so:

In[1]:= p[{3, 4}] p[{5, 6}] p[{1, 4, 6}] p[{2, 3, 5}] //.
         Times[before___p, p[l1_List], between___p, p[l2_List], after___p] /; 
           Intersection[l1, l2] =!= {} :> 
          Times[p[Union[l1, l2]], before, between, after]
Out[1]= p[{1, 2, 3, 4, 5, 6}]
$\endgroup$
2
  • $\begingroup$ Ha! before, between, after sounds funny :) $\endgroup$ Nov 6, 2015 at 2:15
  • $\begingroup$ This worked! Thank you. $\endgroup$ Nov 6, 2015 at 3:28
6
$\begingroup$

You can condition your pattern match with ContainsAny.

rep = {p[list1_] p[list2_] /; ContainsAny[list1, list2] :> p[Union[list1, list2]]};

p[{3, 4}] p[{5, 6}] p[{1, 4, 6}] p[{2, 3, 5}] //. rep
(* p[{1, 2, 3, 4, 5, 6}] *)

p[{3, 4}] p[{5, 6}] p[{8, 10}] p[{1, 4, 6}] p[{2, 3, 5}] //. rep
(* p[{8, 10}] p[{1, 2, 3, 4, 5, 6}] *)

Hope this helps.

$\endgroup$
7
  • $\begingroup$ This does immensely! Thank you!! $\endgroup$ Nov 6, 2015 at 1:35
  • $\begingroup$ this actually doesn't seem to work how it should. Even if I input the example you give it doesn't change it. Do you know what the problem might be? $\endgroup$ Nov 6, 2015 at 1:58
  • $\begingroup$ In a new notebook run ClearAll[p, list1, list2, rep] and then the code above. $\endgroup$
    – Edmund
    Nov 6, 2015 at 2:00
  • $\begingroup$ Same problem. The first just returns p[{3,4}] p[{5,6}] p[{1,4,6}] p[{2,3,5}] $\endgroup$ Nov 6, 2015 at 2:22
  • $\begingroup$ so this works for you when you enter it? I'm assuming it's just something wrong with my setup. $\endgroup$ Nov 6, 2015 at 2:32

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.