Given a string, find the 10 least common alpha-numeric characters within that string.

Output should be formatted with numbers left-padded with spaces so they look like this:

e:      1
t:     16
c:     42
b:    400
z:  50000
a: 100000

Use this to test your program: here

Output for test case:

j:  2
x:  3
q:  9
k: 32
v: 67
c: 73
w: 79
f: 93
b: 94
p: 96

Shortest code wins. You can submit a program or a function.

  • \$\begingroup\$ Do you want a function or a whole program? \$\endgroup\$
    – marinus
    Oct 25, 2012 at 4:14
  • \$\begingroup\$ @marinus: A program or a function, whichever is shorter for you. \$\endgroup\$
    – beary605
    Oct 25, 2012 at 4:23
  • \$\begingroup\$ I presume from your output to the test case that uppercase and lowercase letters are treated as the same? \$\endgroup\$
    – Gareth
    Oct 25, 2012 at 10:31
  • \$\begingroup\$ @Gareth: Yes, they should be treated the same. \$\endgroup\$
    – beary605
    Oct 25, 2012 at 14:17

13 Answers 13


Mathematica, 102 93:


              Last@# &],


         SortBy[Tally@StringCases[ToLowerCase@#, x_?LetterQ :> x <> ":"],
                #[[2]] &], 
         TableAlignments -> Right] &
  • \$\begingroup\$ You beat me to it (and had more streamlined code). \$\endgroup\$
    – DavidC
    Oct 25, 2012 at 18:58
  • \$\begingroup\$ @DavidCarraher But MMa is SO verbose! :( \$\endgroup\$ Oct 25, 2012 at 23:35
  • \$\begingroup\$ I detect a hint of irony in your comment. \$\endgroup\$
    – DavidC
    Oct 26, 2012 at 16:59

Bash, 72

Assuming no single-letter-named files in the current directory; input from stdin:

grep -io [a-z]|sort -f|uniq -ci|sort|head|sed -E 's/(.*)([a-z])/\2:\1/'

Works on Linux, but for some reason, my mac's grep seems to ignore the -i when used with -o (bug or undocumented gotcha?), but the following (78) works:

tr A-Z a-z|grep -o [a-z]|sort|uniq -c|sort|head|sed -E 's/(.*)([a-z])/\2:\1/'

If the output were allowed to be reversed, the sed part could be dropped to save 30 characters in each of the previous solutions.


Java 452 444 433 430

import java.util.*;
interface L{
static void main(String[]a){
Map<Character,Integer>m=new HashMap<>();
for(char c:a[0].toLowerCase().toCharArray())if(96<c&&c<123) m.merge(c,1,(j,i)->j+i);
int l=String.valueOf(m.values().stream().reduce(0,Integer::max)).length();

My first contribution. I know Java will never win this kind of challenges but until now it is at least the shortest java response :)

First argument is used as input. If it contains spaces, it has to be quoted(")


// there is not a lot you get for free, so import you will
import java.util.*;
interface L{
static void main(String[]a) {                 // java main entry point
    Map<Character,Integer> m=new HashMap<>(); // key=character, value=number of occurances in input text
    for(char c:                               // for each character in
        a[0]                                  // take first argument from command line
        .toLowerCase()                        // convert all characters to lowercase
        .toCharArray())                       // convert to array so we can loop over it
      if(96<c&&c<123)                      // accept only a-z
        m.merge(c, 1, (j,i)->j+i);            // fill map, increase corresponding value
    int l=String.valueOf(                     // l: to store length of counter
            m.values().stream()               // loop over counter values
              .reduce(0,Integer::max))        // find max value
            .length();                        // count number of digits of max value

    m.entrySet().stream()                     // loop over the counter map
    .sorted((e,f)->e.getValue()-f.getValue()) // sort the map by value ascending
    .forEachOrdered(                          // loop over the ordered result  
        e->System.out.println(                // print for every entry
            e.getKey()                        // - the key
            +String.format("%"+l+"s",         // - format using l
                 e.getValue())));             //   the value

452 -> 444 : removed spaces

444 -> 433 : class-> interface, public

433 -> 430: 96<c&c<123 (thanks @ceilingcat)

  • \$\begingroup\$ Nice first post, welcome to the site! I don't know Java, but is there a way some of that indentation could be removed to save some bytes? \$\endgroup\$ Oct 29, 2020 at 16:07
  • \$\begingroup\$ I'm senior developer and it kind a hurts to write unreadable code :). But as this challenge is more about the number of bytes, I removed unnecessary spaces. Thanks \$\endgroup\$
    – Conffusion
    Oct 29, 2020 at 16:35
  • 2
    \$\begingroup\$ We also have a Tips for golfing in Java page if you're interested in reading (or contributing!) some. \$\endgroup\$ Oct 29, 2020 at 16:39

APL (Dyalog Unicode), 45 36 bytes


Try it online!

A full program which accepts a string as input. tio link uses polyfills for and ⎕C.

Shortened and tested with help from Bubbler.

-12 bytes from Adám.

Doesn't work on tio due to some problem with ⎕C.(Now works, thanks to Adám's help)


                             ⍥⎕C      lowercase the following:
                                ⎕D,⎕A string of the alphabet and digits
                       ⎕              and the input
                        (∊⊆⊣)         filter out nonalphanumerics
                      ∊               flatten the string
            {⍺':',≢⍵}⌸                create a frequency table for each letter key
   ⌷⍨∘⊂∘⍋∘⌽⍨                          sort the table based on the last row
10↑                                   take the first 10 elements
  • \$\begingroup\$ Gofled a bit: {10↑⌷⍨∘⊂∘⍋∘⌽⍨{⍺':',≢⍵}⌸∊⍵(∊⊆⊣)⍥⎕C⎕D,⎕A} which you can make run on TIO by replacing and ⎕C with polyfills: Ö←{(⍵⍵ ⍺)⍺⍺(⍵⍵ ⍵} ⋄ ∆C←819⌶. Also, since this only uses the argument once, you can save another 2 bytes by converting to a tradfn. \$\endgroup\$
    – Adám
    Oct 29, 2020 at 8:10
  • \$\begingroup\$ @Adám Another interesting use for the ∊⊆⊣ idiom. I'll get it running. \$\endgroup\$
    – Razetime
    Oct 29, 2020 at 8:23
  • 1
    \$\begingroup\$ Listed here. \$\endgroup\$
    – Adám
    Oct 29, 2020 at 8:24

K, 60

{(-:|/#:'f)$f:10#$(!x)[i]!r i:<r:. x:#:'=_x@&x in,/.Q`a`A`n}

Python, 206 199 195 characters

import sys
for c in t:
 if c.isalnum():f[c]=f.get(c,0)+1
s=lambda x:x[1]
for n in h:print n[0]+': '+`n[1]`.rjust(len(`max(h,s)[1]`))

Undoubtedly there is a lot of room for improvement, but here's my first attempt. Produces identical output for the test case provided.

206 -> 199: Removed unnecessary newline and keyword argument

199 -> 195: iteritems()


Javascript, 271 characters

I'm not sure whether this breaks the rules of not (it doesn't justify the numbers in the output, but here's my solution anyway:

c=[];t=128;while(t--)c[t]=[0,t];i=prompt().toLowerCase();for(n=0;n<i.length;x=i.charCodeAt(n++),c[x][0]+=x>96&&x<123);for(n=i=0,c=c.sort(function(a,b){return(a[0]-b[0])});n<10;i++)if(c[i][0]>0){console.log(String.fromCharCode(c[i][1])+": "+("  "+c[i][0]).slice(-2));n++}

I'm pretty sure it can be simplified (I won't win with this character count :P), but now I can't find anything.

Okay, so I completely forgot that the padding was actually a requirement :O Corrected that and fixed a bug. (250 -> 271)


Haskell (229)

import Char
import Data.List
k x=[(l$z(==m)x,m)|m<-x]
s z=[b:':':take(1+(maximum$map(l.t.fst)z)-l(t a))(repeat ' ')++t a++"\n"|(a,b)<-z]
main=interact$concat.s.take 10.sort.nub.k.map toLower.z isAlphaNum

Perl, 86 chars

given string is in $_


Python, 144

import os
for c in a:print c+': %%%ii'%len(`n(a[-1])`)%n(c)
  • \$\begingroup\$ I just proposed an edit that saves you 14 characters by switching to the 'raw_input()' function. \$\endgroup\$
    – ESultanik
    Oct 25, 2012 at 14:25
  • \$\begingroup\$ @ESultanik The problem is that raw_input() terminates on newlines, so it would stop after the first line of input in the supplied test case. \$\endgroup\$
    – Strigoides
    Oct 25, 2012 at 15:38
  • \$\begingroup\$ @Strigoides: Good point; I missed that the input could have newlines. My fault for not looking at the test cases. \$\endgroup\$
    – ESultanik
    Oct 25, 2012 at 15:48
  • \$\begingroup\$ print c+': %%%ii'%len(n(a[-1]))%n(c) saves 3 characters \$\endgroup\$
    – Daniel
    Oct 27, 2012 at 9:47

JavaScript 1.8 (ES6) 186

  s.slice(0,10).map(x=>x+': '+('      '+n[x]).slice(-(n[s[9]]+'').length))

Jelly, 22 bytes


Try it online!

Doesn't output with a : on each row, but given that isn't explicitly specified in the spec (compared to the left padding), I assumed this was OK. 26 bytes to require separating by :.

How it works

Øa;ØD - Helper link. Yield a constant value "abc...xyz012...789"
Øa    - Yield "abc...xyz"
   ØD - Yield "0123456789"
  ;   - Concatenate

ŒlċⱮ¢¢żPƇ0ị$Þḣ⁵G - Main link. Takes a string S on the left
Œl               - Convert S to lowercase
    ¢            - Yield "abc...789"
   Ɱ             - For each character:
  ċ              -   Count occurrences in S
     ¢           - Yield "abc...789"
      ż          - Zip with occurrences
        Ƈ        - Keep characters where:
       P         -   There is at least 1 occurrence in S
           $Þ    - Sort by:
         0ị      -   Number of occurrences
             ḣ⁵  - Take the first 10
               G - Convert into a grid format
  • \$\begingroup\$ since all the other answers do output with a : character, I think it's a better idea to post the 26 byte version. \$\endgroup\$
    – Razetime
    Oct 29, 2020 at 6:52

Japt v2.0a0 -R, 28 bytes

Yet another old challenge hindered by an unnecessarily cumbersome output format.

r\W v ü ñʮάpZÊïA yù ®q": 

Try it (Note: I'm passing the input in the header here so it can be enclosed in backticks, allowing for the inclusion of both single & double quotes. Doing so, however, makes no difference to the code or byte count.)

r\W v ü ñʮάpZÊïA yù ®q":      :Implicit input of string
r                                :Remove
 \W                              :  /[^A-Z0-9]/gi
    v                            :Lowercase
      ü                          :Group & sort
        ñ                        :Sort by
         Ê                       :  Length
          ®                      :Map each Z
           Î                     :  First character
            ¬                    :  Split
             p                   :  Push
              ZÊ                 :    Length of Z
                Ã                :End map
                 ¯               :Slice to
                  A              :  10th element
                    y            :Transpose
                     ù           :Left pad each sub array with spaces to the length of the longest and implicitly transpose back
                       ®         :Map
                        q":      :  Join with ": "
                                 :Implicit output joined with newlines
  • \$\begingroup\$ link says Error: URI too long \$\endgroup\$
    – Razetime
    Oct 29, 2020 at 6:51
  • \$\begingroup\$ Fixed that earlier, @Razetime - thanks. \$\endgroup\$
    – Shaggy
    Oct 29, 2020 at 16:21

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.