5
$\begingroup$

I have a list of pairs of strings: myPairsList. I wish to Select all the pairs that do not contain "A" or "B". Unlike functions such as Cases that use patterns as input, the function Select uses a criterion ("crit") as input.

A verbose way to execute my desired selection is:

Select[myPairsList, (#[[1]] != "A") &&
  (#[[1]] != "B") && (#[[2]] != "A") && (#[[2]] != "B") &]

{{"X", "Y"}, {"Y", "X"}}

Perhaps a more elegant way to execute the selection is:

Select[myPairsList, (! MemberQ[{"A", "B"}, #[[1]]]) && 
  (! MemberQ[{"A", "B"}, #[[2]]]) &]

{{"X", "Y"}, {"Y", "X"}}

But, what if I want to express the selection as "the first element is neither "A" nor "B", and the second element is neither "A" nor "B""?

To do that, I tried the following:

Select[myPairsList, (#[[1]] != ("A" || "B")) && (#[[2]] != ("A" || "B")) &]
Select[myPairsList, (#[[1]] != ("A" | "B")) && (#[[2]] != ("A" | "B")) &]

{}

{}

But, as you can see, I don't obtain my desired output, so I'm clearly using the incorrect syntax. So what is the correct way to express "not equal to A or B"?

$\endgroup$
3
  • 5
    $\begingroup$ Select[myPairsList, FreeQ[#, "A" | "B"] &] $\endgroup$
    – Bob Hanlon
    Commented Aug 28, 2023 at 17:27
  • $\begingroup$ Are your strings always single character strings? $\endgroup$
    – lericr
    Commented Aug 28, 2023 at 17:29
  • $\begingroup$ @lericr That's a good point. No, my strings are not always single character strings. $\endgroup$
    – Andrew
    Commented Aug 28, 2023 at 17:47

2 Answers 2

8
$\begingroup$

Example input:

SeedRandom[1];
myPairsList = RandomChoice[{"A", "B", "X", "Y"}, {40, 2}]

{{"Y", "B"}, {"A", "B"}, {"B", "A"}, {"A", "A"}, {"B", "Y"}, {"A", 
  "A"}, {"A", "A"}, {"X", "A"}, {"B", "X"}, {"A", "A"}, {"Y", 
  "Y"}, {"Y", "B"}, {"B", "A"}, {"A", "B"}, {"Y", "A"}, {"X", 
  "A"}, {"B", "B"}, {"Y", "Y"}, {"Y", "X"}, {"Y", "X"}, {"A", 
  "B"}, {"Y", "Y"}, {"A", "B"}, {"A", "B"}, {"A", "Y"}, {"A", 
  "X"}, {"Y", "A"}, {"X", "X"}, {"A", "B"}, {"Y", "X"}, {"B", 
  "X"}, {"A", "A"}, {"A", "X"}, {"B", "X"}, {"B", "A"}, {"X", 
  "Y"}, {"B", "B"}, {"B", "A"}, {"Y", "X"}, {"A", "Y"}}

Some of the ways could be:

Select[ContainsNone[{"A", "B"}]][myPairsList]

As Bob Hanlon suggested:

Select[FreeQ["A" | "B"]][myPairsList]

or its counterpart:

Select[Not@*MemberQ["A" | "B"]][myPairsList]

DeleteCases[myPairsList, {x___, OrderlessPatternSequence["A" | "B"], 
  y___}]

Select[Nor[MemberQ[#, "A"], MemberQ[#, "B"]] &][myPairsList]

Result:

{{"Y", "Y"}, {"Y", "Y"}, {"Y", "X"}, {"Y", "X"}, {"Y", "Y"}, {"X",
"X"}, {"Y", "X"}, {"X", "Y"}, {"Y", "X"}}

$\endgroup$
2
  • $\begingroup$ This is great. But I forgot to mention in my original post that I would prefer that the solution be compatible with Mathematica 9 and later. It looks like ContainsNone was introduced in 10.2. $\endgroup$
    – Andrew
    Commented Aug 28, 2023 at 17:44
  • 1
    $\begingroup$ I realized that as soon as I had typed it in. Please see update. $\endgroup$
    – Syed
    Commented Aug 28, 2023 at 17:46
4
$\begingroup$

Assuming that the strings are not always single characters, we may want to use some string specific functions, specifically StringFreeQ.

Select[myPairsList, Apply[And]@*StringFreeQ[{"A", "B"}]]

StringFreeQ can work on a list (your pairs are just lists), but it keeps the list structure, so we need to do a logical and on that list, thus the Apply[And].

$\endgroup$

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.