Suppose I have a list

l = {a, b, c, d, e, f....}

I would like to remove one of each pair {x,y} if some function check[x,y] returns xor y (or do nothing for that particular pair if the function returns {}). The order of the list is important. For example, if

check[c,e] === c;
check[a,f] === f;

and check on any other combination is empty, the final list should be

{a, b, d, e, ...}

I know how to write a for loop and do index-based removal, but is it a slicker way to do it using Mathematica's list manipulation functions?

EDIT: The check function should be non-overlapping in my usage, but in case if there is problematic overlap, say

check[a,e] === a;
check[a,f] === f;

both e and f should remain, since after removal of a (assuming position of a is earlier than f), there is no pair that can be formed with {a,f}.

  • $\begingroup$ I am presuming Check is intended to be your own, custom function but that name is already in use. User symbols should start with lower case letters. $\endgroup$ – Mr.Wizard Oct 6 '12 at 8:37
  • $\begingroup$ What happens if check[a,b] == a and check[a,d] == a? Is it sufficient to remove a? Should the second check be performed at all? $\endgroup$ – Mr.Wizard Oct 6 '12 at 8:44
  • $\begingroup$ @Mr.Wizard: Good catch! Question edited. $\endgroup$ – polyglot Oct 6 '12 at 8:53
  • 1
    $\begingroup$ Now I am wondering why f is removed and not a -- should the element that is not returned be removed? $\endgroup$ – Mr.Wizard Oct 6 '12 at 9:05
  • $\begingroup$ It depends on definition of check of course; question again edited for consistency. (It proves that I should go to bed instead...) $\endgroup$ – polyglot Oct 6 '12 at 9:10

You said that your check should be non-overlapping. For that simplified case I believe this works:

check[c, e] = c;
check[a, f] = f;
check[__] = {};

lst = {a, b, c, d, e, f};
  Alternatives @@ Flatten[check @@@ Subsets[lst, {2}]]

{a, b, d, e}

I'm still working on the more complex version.


Here's one implementation:

l = {a, b, c, d, e, f};
check[x_, y_] := If[MemberQ[l, x] && MemberQ[l, y], RandomChoice[{x, y}]]
Fold[DeleteCases, l, {check[c, e], check[a, f]}]

{a, b, d, e}


A version that checks all subset pairs:

l = {a, b, c, d, e, f};
s = Subsets[l, {2}];
check[{x_, y_}] := If[MemberQ[l, x] && MemberQ[l, y], RandomChoice[{x, y}]]
(l = DeleteCases[l, check[#]]) & /@ s;


As ployglot's edit observes, progressively removing check results from l results in less matches than using Fold, i.e.

Fold[DeleteCases, l, check[#] & /@ s] 

{ }

  • $\begingroup$ You seem to have a very different interpretation of the question. Would you take a look at my present answer and tell me if you still think you've got it right? (I don't mean that condescendingly; rather I'm asking because I don't know for sure that I've got it right.) $\endgroup$ – Mr.Wizard Oct 6 '12 at 9:36
  • $\begingroup$ @ Mr.Wizard - seems to depend how specific polyglot intends his example to be. $\endgroup$ – Chris Degnen Oct 6 '12 at 10:03

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.