Highest or Lowest Occurrences?

Jelly, 31 bytes

ØṖḟØBṭØBUs26¤f€³Lİ⁴¡$ÐṀFf
¹⁶Ç?€

Try it online!

The boolean values are 2 and 1 (or any other positive even/odd pair), which represent True and False respectively. I will try to add an explanation after further golfing.

Thanks to caird coinheringaahing for saving 2 bytes, and to Lynn for saving 4 bytes! Thanks to one of Erik's tricks, which inspired me to save 4 bytes!

How it works

Note that this is the explanation for the 35-byte version. The new one does roughly the same (but tweaked a bit by Lynn), so I won't change it.

ØBUs26f€³µ³ḟØBW,µẎLİ⁴¡$ÐṀF - Niladic helper link.
ØB                         - String of base digits: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
                             abcdefghijklmnopqrstuvwxyz'. 
  U                        - Reverse.
   s26                     - Chop into sublists of length 26, preserving shorter
                             trailing substrings.
      f€³                  - For each, keep the common characters with the input.
            ØB             - Base digits.
          ³ḟ               - Get the signs in the input. Filter the characters of the
                             input that aren't alphanumeric.
              W,µẎ         - Concatenate (wrap, two element list, tighten).
                       ÐṀ  - Keep the elements with maximal link value.
                  L        - Length.
                    ⁴¡     - Do N times, where N is the second input.
                   İ       - Inverse. Computes 1 ÷ Length. 2 maps to the length itself,
                             because 1 ÷ (1 ÷ Length) = length; 1 yields
                             (1 ÷ Length), swapping the maximal numbers with minimal ones.
                         F - Flatten.

¹⁶e¢$?€ - Main link.
      € - For each character.
   e¢?  - If it is contained by the last link (called niladically), then:
¹       - Identity, the character itself, else:
 ⁶      - A space.

Python 2, 166 158 bytes

t=lambda c:('@'<c<'[','`'<c<'{','/'<c<':',1-c.isalnum())
def f(s,b):x=map(sum,zip(*map(t,s)));print''.join([' ',c][x[t(c).index(1)]==sorted(x)[-b]]for c in s)

Try it online!


R, 193 186 179 158 bytes

-7 bytes thanks to NofP and his suggestion of cbind

-6 bytes using outer, -1 byte switching [^a-zA-Z0-9] with [[:punct:]]

-21 bytes thanks to MickyT for pointing out a list of characters is allowed

function(S,B){y=outer(c("[a-z]","[A-Z]","\\d","[[:punct:]]"),S,Vectorize(grepl))
S[!colSums(y[(s=rowSums(y))=="if"(B,max,min)(s),,drop=F])]=" "
cat(S,sep='')}

Verify all test cases

Takes 1/T as truthy (max) and 0/F as falsey (min), and takes S as a list of single characters.

Try it online!

In my original version (with NofP's suggestions), the matrix y is constructed by evaluating grepl(regex, S) for each regex, then concatenating them together as columns of a matrix. This results in multiple calls to grepl, but as S is fixed, it seemed that something else needed to be done. As I noted:

There are potentially shorter approaches; mapply, for example:

y=mapply(grepl,c("[a-z]","[A-Z]","\\d","[^a-zA-Z0-9]"),list(S))

unfortunately, this will not simplify as a matrix in the 1-character example of "A".

I used outer rather than mapply, which always returns an array (a matrix in this case), and was forced to Vectorize grepl, which is really just an mapply wrapper around it.

I also discovered the predefined character group [:punct:] which matches punctuation (non-space, non-alphanumeric) characters.