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$ 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.