21
\$\begingroup\$

Definition

Given some string return an integer whose digits are the number ocurrences of a-z (case insensitive, in alphabetical order) in that string. Any character with 0 instances is skipped. Characters with 10 or more instances will define 2 or more digits of the returned integer. For example, aaaaaaaaaaaaaaaaaaaaaaaaaaad (27 a's followed by d) will return 271.

Input

A single string with one or more letters

Output

An integer or a string representing an integer

Test Cases

Input Output
acfzzA 2112
Hello World! 1113211
---!&*#$ invalid input, any result is acceptable
---!&*#$a 1
aaaaaaaaaaaaaaaaaaaaaaaaaaad 271
aaaaaaaaaad 101
cccbba 123
abbccc 123

This is code-golf, so the shortest answer in bytes wins! Standard loopholes and rules apply. Tie goes to first poster.

\$\endgroup\$
12
  • 3
    \$\begingroup\$ Why did you move this from the sandbox so soon? \$\endgroup\$
    – pxeger
    Commented Dec 15, 2021 at 3:02
  • 4
    \$\begingroup\$ Shouldn't "Hello World!" be 1132111 instead of 1113211, or the order doesn't count? \$\endgroup\$
    – Kaddath
    Commented Dec 15, 2021 at 8:14
  • 5
    \$\begingroup\$ @pajonk nowhere in the question it is specified that it should be in alphabetical order.. and many answers don't sort the result so it may be a little late to add the restriction now \$\endgroup\$
    – Kaddath
    Commented Dec 15, 2021 at 12:20
  • 2
    \$\begingroup\$ @Kaddath the intention was that the result should be specified in alphabetical order. That is what I meant by "a-z" although I should have been more clear \$\endgroup\$
    – Nigel
    Commented Dec 15, 2021 at 18:19
  • 1
    \$\begingroup\$ @DLosc I added a test case for this as well as additional test cases to verify alphabetical order counting \$\endgroup\$
    – Nigel
    Commented Dec 16, 2021 at 23:11

35 Answers 35

7
\$\begingroup\$

Python 2, 64 bytes

f=lambda s,c=65:91/c*s and'%.d'%s.upper().count(chr(c))+f(s,c+1)

Try it online!

\$\endgroup\$
1
  • 2
    \$\begingroup\$ That %.d is wizardry! \$\endgroup\$
    – xnor
    Commented Dec 15, 2021 at 4:08
7
\$\begingroup\$

C, 137, 124, 90, 88 bytes

Thank you @AnttiP and @tsh for suggestions!

s[99];main(c){while(c-10)s[(c=getchar())&~32]++;for(c=64;c-90;)s[++c]&&printf("%d",s[c]);}

less golfed version:

s[99];

int main(c){
       
    while(c-10)
        s[(c=getchar())&~32]++;

    for(c=64;c-90;)
        s[++c]&&printf("%d",s[c]);
}

Try it online!

\$\endgroup\$
7
  • \$\begingroup\$ Welcome to Code Golf! Nice first answer. \$\endgroup\$
    – rydwolf
    Commented Dec 15, 2021 at 4:57
  • 2
    \$\begingroup\$ Welcome to Code Golf! You can convert to uppercase with a bitwise and, saving 13 bytes in the while loop: while((c=getchar())-10)s[c&95]++; \$\endgroup\$
    – AnttiP
    Commented Dec 15, 2021 at 7:19
  • \$\begingroup\$ 90 bytes: s[99];main(c){while(c-10)s[(c=getchar())&~32]++;for(c=64;c-90;)s[++c]&&printf("%d",s[c]);} \$\endgroup\$
    – tsh
    Commented Dec 15, 2021 at 7:27
  • \$\begingroup\$ Thank you all! Really appreciate that! AnttiP, thank you for that! I'll take a look on bit wise operations... @tsh, wow thank you for that! Really insightful! How should I proceed? I saw some people editing their posts to shave some bytes, but it was never that many... And one final note, I couldn't get it to work on TIO, what does the -w flag do? Just ignores the warnings? \$\endgroup\$ Commented Dec 15, 2021 at 13:22
  • \$\begingroup\$ Seems to fail the ---!&*#$a testcase \$\endgroup\$ Commented Dec 19, 2021 at 16:43
7
\$\begingroup\$

Python 3.8, 76 bytes:

lambda x:''.join(str(i)for a in range(97,123)if(i:=x.lower().count(chr(a))))

Try it online!

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Maybe int('0'+) is not necessary to this question? \$\endgroup\$
    – tsh
    Commented Dec 15, 2021 at 3:52
  • \$\begingroup\$ @tsh It is if the input does not contain any letters i.e ---!&*#$. '0' pads the result in the event ''.join returns an empty string. \$\endgroup\$
    – Ajax1234
    Commented Dec 15, 2021 at 3:54
  • \$\begingroup\$ @Ajax1234 Inputs without letters are explicitly invalid; I'd assume that erroring falls under "any result". Also note that output doesn't have to be of an actual integer type \$\endgroup\$ Commented Dec 15, 2021 at 3:56
  • 1
    \$\begingroup\$ @UnrelatedString Thanks, updated the post \$\endgroup\$
    – Ajax1234
    Commented Dec 15, 2021 at 3:59
  • \$\begingroup\$ (You can also shave a byte off by folding to uppercase.) \$\endgroup\$ Commented Dec 15, 2021 at 4:07
6
\$\begingroup\$

Charcoal, 10 bytes

⭆α⪫↨№↥θιχω

Try it online! Link is to verbose version of code. Explanation:

 α          Predefined variable uppercase alphabet
⭆           Map over letters and join
    №       Count of
       ι    Current letter in
     ↥      Uppercased
      θ     Input string
   ↨    χ   Convert to base 10
  ⪫      ω  Join digits together

Charcoal's arbitrary base conversion returns an empty list for an input of zero, which is the easiest way to map zero to an empty string.

\$\endgroup\$
4
\$\begingroup\$

Vyxal, 44 bitsv2, 5.5 bytes

Ǎ⇩sĠ@ṅ

Try it Online!

Explained

Ǎ⇩sĊvtṅ
Ǎ       # keep only letters of the alphabet
 ⇩      # and convert to lowercase
  sĊ    # sort that and get the counts of each letter - this returns [[letter, count of letter] for each letter
    vtṅ # join the counts of letters on ""
\$\endgroup\$
4
\$\begingroup\$

PHP, 66 bytes

<?=join(count_chars(preg_replace('~\W~','',strtolower($argn)),1));

Try it online!

A rarely useful builtin function, but it turns out satisfying when it does

\$\endgroup\$
2
  • \$\begingroup\$ Nine one. I read this and was like "oh yeah, that's count_chars()" . There should be something cheaper than preg_replace() and strtolower() but probably isn't! \$\endgroup\$
    – 640KB
    Commented Dec 15, 2021 at 14:30
  • \$\begingroup\$ @640KB haven't found shorter yet.. I was also experimenting the other way round to have the alphabetical order, not that far but still longer. If you have an idea with it: for($c=a;$c!=aa;$c++)($i=count(preg_split("~$c~i",$argn))-1)?$r.=$i:0;echo$r; for 77 bytes \$\endgroup\$
    – Kaddath
    Commented Dec 15, 2021 at 14:50
4
\$\begingroup\$

R, 78 69 bytes

Or R>=4.1, 62 bytes by replacing the word function with \.

Edit: -9 bytes inspired by @Giuseppe's answer.

function(s)cat(table(utf8ToInt(gsub("[^a-z]","",tolower(s)))),sep="")

Try it online!

Prints the resulting number like in @Giuseppe's answer.

\$\endgroup\$
1
  • \$\begingroup\$ Ah, I should have suggested the cat here especially since the tabulate is longer now! \$\endgroup\$
    – Giuseppe
    Commented Dec 15, 2021 at 13:41
4
\$\begingroup\$

Wolfram Language (Mathematica), 54 52 bytes

""&@@@Array[ToString/@Counts@LetterNumber@#,26]<>""&

Try it online!

                             LetterNumber@#             a->1,...,z->26, others->0
                      Counts@                           letter counts
      Array[                               ,26]           for a,...,z
""&@@@                                                    (don't include missing letters)
            ToString/@                         <>""     concatenate
\$\endgroup\$
4
\$\begingroup\$

Perl 5 + -p, 23 bytes

s/\pl/$\.=s!$&!!gi/ge}{

Try it online!


Perl 5 + -n, 23 bytes

s/\pl/print s!$&!!gi/ge

Try it online!

\$\endgroup\$
4
\$\begingroup\$

bash, 64 44 bytes

Original Solution (64 Bytes)

Fairly simple tr-based solution - bash probably isn't a good way to make a competitive answer, but I had fun doing it!

tr [A-Z] [a-z]|tr -dc [a-z]|grep -o .|sort|uniq -c|tr -dc [0-9]

Depending on how you want to count characters, it could be more than 64 when including the input to this. A very simple case would be:

echo my-input-string|tr [A-Z] [a-z]|tr -dc [a-z]|grep -o .|sort|uniq -c|tr -dc [0-9]

which really only adds six characters at best and eight if you have to single-quote the input string.

Explanation:

tr [A-Z]  [a-z]   # Convert all capitals to lowercase in the input stream
tr -dc [a-z]      # Delete everything that isn't a lowercase letter
grep -o .         # Output every character on its own line
sort | uniq -c    # Get a two-column output of all unique characters and their frequencies
tr -dc [0-9]      # Delete everything that isn't a digit

44 Byte Solution (by @Digital Trauma)

grep -io [a-z]|sort -i|uniq -ci|tr -dc [0-9]

Among other improvements, this bash solution utilizes some case-insensitive options for utilities such as sort and uniq.

Here's @Digital Trauma's Try It Online

\$\endgroup\$
7
  • 2
    \$\begingroup\$ Welcome to Code Golf, and nice answer! I don't remember the rules for I/O most bash answers here use, but the 64 byte one should be fine. \$\endgroup\$
    – rydwolf
    Commented Dec 16, 2021 at 20:08
  • 1
    \$\begingroup\$ Instead of the second tr, we could get grep to select only letters: tr [A-Z] [a-z]|grep -o '[a-z]'|sort|uniq -c|tr -dc [0-9] (56 chars). \$\endgroup\$ Commented Dec 17, 2021 at 7:55
  • 1
    \$\begingroup\$ You might mention that this is for ASCII and similar codings, where letters are consecutive. [a-z] may mean something different to what you expect! \$\endgroup\$ Commented Dec 17, 2021 at 7:55
  • 1
    \$\begingroup\$ 44 bytes: grep -io [a-z]|sort -i|uniq -ci|tr -dc [0-9] \$\endgroup\$ Commented Dec 17, 2021 at 23:09
  • 1
    \$\begingroup\$ Bash (and zsh) often compare fairly well against other non-golfing languages, though perl often does better in the hands of an expert. \$\endgroup\$ Commented Dec 17, 2021 at 23:14
3
\$\begingroup\$

Factor + spelling, 56 bytes

[ >lower ALPHABET counts values [ present ] map-concat ]

The counts word postdates Factor build 1525, the one TIO uses, so here's a screenshot of running the above code in build 2101's listener:

A screenshot of running the above code snippet

Explanation

                        ! "acfzzA"
>lower                  ! "acfzza"
ALPHABET                ! "acfzza" "abcdefghijklmnopqrstuvwxyz"
counts                  ! { { 97 2 } { 99 1 } { 102 1 } { 122 2 } }
values                  ! { 2 1 1 2 }
[ present ] map-concat  ! "2112"
\$\endgroup\$
3
\$\begingroup\$

BQN, 30 28 bytesSBCS

{∾•Fmt¨×⊸/+˝(⥊𝕩-⌜"aA")=⌜↕26}

Run online!

↕26 Range from 0 to 25.
⥊𝕩-⌜"aA" Differences between each of the characters in the input and a or A.
=⌜ Equality table between those two vectors.
Sum the columns.
×⊸/ Keep the values with sign 1 (or: remove the zeros)
∾•Fmt¨ Convert each value to a string and join.

A slightly different approach using Bins Down at 29 bytes:

{∾•Fmt¨×⊸/»1↓/⁼27↕⊸⍋⥊𝕩-⌜"aA"}

Run online!

\$\endgroup\$
3
\$\begingroup\$

R, 75 72 bytes

function(s,x=tabulate((y=utf8ToInt(s))%%32*(y>64),26))cat(x[!!x],sep="")

Try it online!

Prints the result. For invalid input, prints nothing.

-3 bytes thanks to Dominic van Essen.

Test harness taken from pajonk's answer.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ 69 bytes... \$\endgroup\$ Commented Dec 15, 2021 at 13:42
  • \$\begingroup\$ @Dominicvanessen that would capture the handful of characters between Z and a, right? \$\endgroup\$
    – Giuseppe
    Commented Dec 15, 2021 at 13:52
  • \$\begingroup\$ oh, yeah, sorry, you'll need another ,26 then, so actually 72 bytes then... \$\endgroup\$ Commented Dec 15, 2021 at 13:57
3
\$\begingroup\$

JavaScript (ES6), 63 bytes

Expects an array of characters.

a=>a.map(c=>o[i=parseInt(c,36)]=-~o[i],o=[])|o.slice(10).join``

Try it online!

Commented

a =>                // a[] = input array
a.map(c =>          // for each character c in a[]:
  o[                //   update o[]:
    i =             //     let i be the result of
    parseInt(c, 36) //     c parsed in base-36
                    //     which gives 0 to 9 for [0-9],
                    //     10 to 35 for [a-z] and [A-Z]
                    //     and NaN for anything else
                    //     (o[NaN] is not an entry of the array but
                    //     an object property which will be ignored
  ] =               //     by join())
    -~o[i],         //     increment it / set it to 1 if it's undefined
  o = []            //   initialize o[] to an empty array
) |                 // end of map()
o.slice(10)         // ignore the first 10 entries
.join``             // join the remaining ones; undefined values are
                    // coerced to empty strings
\$\endgroup\$
3
\$\begingroup\$

PowerShell, 56 50 bytes

%{-join($_|% T*y|% *g|sort|group|? N* -m \w|% C*)}

Input comes from the pipeline.

Try it online!

Try it in a PS console:

$strings = 'acfzzA', 'Hello World!', '---!&*#$', '---!&*#$a', 'aaaaaaaaaaaaaaaaaaaaaaaaaaad', 'aaaaaaaaaad', 'cccbba', 'abbccc'
$result = $strings |
%{-join($_|% T*y|% *g|sort|group|? N* -m \w|% C*)}
1..($strings.Length-1)|%{"'$($strings[$_])' --> '$($result[$_])'"}

-5 by rearranging the first version %{-join($_|% T*y|% *g|?{$_-match'\w'}|sort|group|% C*t)}; moving the "match" filter after the "group" allows the use of the "<Property> <Operator> <Value>" syntax of Where-Object instead of using a FilterScript.
-1 by removing the unnecessary "t" from "% C*t"

Explanation

%{...} "%" is an alias for the cmdlet "ForEach-Object", which accepts input from the pipeline and processes each incoming object inside the ScriptBlock {...}
-join(...) Unary operator which will join the all the character counts returned inside the expression
% T*y takes the input string and calls its method "ToCharArray()", turning the string into an array of single characters.
% *g takes the array of characters and turns them back to single-character strings by invoking ToString() (the only method matching "*g"), because Group-Object is case sensitive for characters, but not for strings.
sort is an alias for Sort-Object, which will sort the characters.
group is an alias for Group-Object, which will group the characters, and return objects with a Count property for each character; returns GroupInfo objects.
? N* -m \w "?" is an alias for "Where-Object", the rest expands to "-Property 'Name' -match '\w'" - this lets only objects pass where the Name property (which contains the grouped character) consists only of word (\w) characters. PS allows for partial named parameters, so -m will be identified as -match.
% C* gets the property "Count" (the only one starting with C) of the GroupInfo objects.
All the counts will now be collected and joined to a single string; output is implicit.

Ungolfed

ForEach-Object -Process {
    -join (                                             # Will join the counts of all characters produced inside the brackets into a single string
        $_ |                                            # Input string
            ForEach-Object -MemberName ToCharArray |    # input string to single chars
            ForEach-Object -MemberName ToString |       # input chars to single-char strings
            Sort-Object |
            Group-Object |                              # group same characters
            Where-Object -Property 'Name' -match '\w' | # let only word characters pass ("Name" contains the string/character used to group)
            ForEach-Object -MemberName Count            # get only the count of the grouped objects
    )
}
\$\endgroup\$
4
  • \$\begingroup\$ Your code is a Powershell snippet, not a program or a function. Try save your code to a standalone PS1-file and run it. \$\endgroup\$
    – mazzy
    Commented Dec 15, 2021 at 15:10
  • 1
    \$\begingroup\$ Sorry, but I beg to differ. This is a call of the cmdlet ForEach-Object (%), passing a scriptblock to the (unnamed) -Process argument. It accepts input either by the named argument -InputObject, or through stdin/the pipeline. The lines around the main code above are just eye candy. All that is actually required is piping the value to process to the function: 'acfzzA' | %{...}, which has the same effect as %{...} -i 'acfzzA'. This can be pasted directly into a PS console (which I consider valid, since PS is a Shell, after all), and it will show the result. Correct me if I'm wrong. \$\endgroup\$
    – user314159
    Commented Dec 15, 2021 at 22:12
  • \$\begingroup\$ yes, you are right, of course. The question is How to count bytes of your code for the CodeGolf. If you want to use the "names argument -InputObject" or the constant 'acfzzA' then you need to include to your CodeGolf code. \$\endgroup\$
    – mazzy
    Commented Dec 16, 2021 at 4:20
  • \$\begingroup\$ Not sure what you're after here, sorry. The function ForEach-Object (aka "%") takes input from stdin, which is a perfectly allowed method. So you take the input, for example 'acfzzA', and pipe it to said function. Why would the input count towards the byte count? This can be pasted into a PS console as is: 'acfzzA', 'Hello World!' | %{-join($_|% T*y|% *g|?{$_-match'\w'}|sort|group|% C*t)} Two test cases are piped to the code that processes it, which starts at %{. I don't see any functional difference to, say, the Java or JavaScript solutions here. \$\endgroup\$
    – user314159
    Commented Dec 16, 2021 at 7:43
3
\$\begingroup\$

Husk, 11 9 8 bytes

Edit: -2 bytes but +1 (bug fix) for a net -1 byte, all thanks to Razetime

ṁosLk_f√

Try it online!

Digits are in alphabetical order of each letter.

       f√    # filter for only letters,
     k_      # and group letters by lowercase value;
 ṁo          # now map to each group & combine the results:
    L        #  get the length
   s         #  and convert to a string
\$\endgroup\$
2
  • \$\begingroup\$ use k_ for -2, dmL doesn't work since count of any letter can be >10, so ṁosL or better equivalent should be there \$\endgroup\$
    – Razetime
    Commented Dec 17, 2021 at 13:42
  • \$\begingroup\$ @Razetime - double thanks! And well-spotted for the >10 bug (which worked for the test cases, but it's obvious now you've pointed it out...) \$\endgroup\$ Commented Dec 17, 2021 at 14:38
3
\$\begingroup\$

05AB1E, 7 bytes

lDáêS¢J

Try it online!

-2 bytes and fix thanks to @KevinCruijssen and @ovs

\$\endgroup\$
4
  • 1
    \$\begingroup\$ This counts non-alphabetic characters as well and returns in the order of the input string instead of alphabetic order \$\endgroup\$
    – ovs
    Commented Dec 15, 2021 at 9:16
  • 1
    \$\begingroup\$ Your current program could be lDÙS¢J for 6 bytes. And to fix the issue mentioned by @ovs above, you can replace the Ù with áê: try it online or verify all test cases. \$\endgroup\$ Commented Dec 15, 2021 at 11:16
  • \$\begingroup\$ @KevinCruijssen,ovs thanks for the fix \$\endgroup\$
    – Wasif
    Commented Dec 19, 2021 at 8:37
  • \$\begingroup\$ Actually, it can be 6 bytes by removing the S and taking the input as a list of characters. \$\endgroup\$ Commented Dec 19, 2021 at 10:46
3
\$\begingroup\$

Python3, 72 70 67 87 bytes

lambda x:''.join(map(str,map((x:=x.lower()).count,sorted(filter(str.isalpha,set(x))))))

Try it online

\$\endgroup\$
1
2
\$\begingroup\$

Jelly, 8 bytes

ŒufØAṢŒɠ

Try it online!

Jelly, 8 bytes

ŒuċⱮØA¹Ƈ

Try it online!

Both as full programs, taking advantage of Jelly's automatic smash-printing behavior.

\$\endgroup\$
2
\$\begingroup\$

JavaScript (Node.js), 64 bytes

s=>s.sort().join(o='').replace(/([a-z])\1*/gi,c=>o+=c.length)&&o

Try it online!

Based off Arnauld's answer. Takes input as a character array.

Sort, join, match runs of one character and append that to o, and yield that at the end.

\$\endgroup\$
2
\$\begingroup\$

APL+WIN, 48 44 bytes

Prompts for string

10⊥((+/(48+m)∘.=n)++/(m←17+⍳26)∘.=n←⎕av⍳⎕)~0

Try it online! Thanks to Dyalog Classic

\$\endgroup\$
2
\$\begingroup\$

Haskell, 120 84 73 bytes

f x=do(v,u)<-zip['a'..'z']['A'..];1:r<-[[1|k<-x,v==k||u==k]];show$sum$1:r

Try it Online!

-36 bytes thanks to Unrelated String

-11 bytes thanks to Wheat Wizard

\$\endgroup\$
7
2
\$\begingroup\$

Scala, 64 bytes

s=>('A'to'Z').map(c=>s.count(_.toUpper==c)).filter(_>0).mkString

Try it online!

\$\endgroup\$
2
\$\begingroup\$

PowerShell 6+, 47 46 bytes

-1 byte thanks @Julian

-join($args|?{$_-in'a'..'z'}|group{"$_"}|% c*)

Try it online!

\$\endgroup\$
3
  • 1
    \$\begingroup\$ This expects an array of characters as input, not "A single string with one or more letters". \$\endgroup\$
    – user314159
    Commented Dec 17, 2021 at 15:30
  • \$\begingroup\$ Thanks. The CodeGolf allows any string representation. I think it will be useful for you to read the codegolf.meta.stackexchange.com \$\endgroup\$
    – mazzy
    Commented Dec 18, 2021 at 4:05
  • 1
    \$\begingroup\$ You can drop the last t \$\endgroup\$
    – Julian
    Commented Jan 28, 2022 at 22:37
1
\$\begingroup\$

Ruby, 48 bytes

->s{((?A..?Z).map{|c|s.upcase.count(c)}-[0])*''}

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ .count(c) -> .count c \$\endgroup\$ Commented Dec 15, 2021 at 7:07
1
\$\begingroup\$

Retina 0.8.2, 24 bytes

T`Llp`LL_
O`.
(.)\1*
$.&

Try it online! Link includes test cases. Explanation:

T`Llp`LL_

Uppercase all letters and delete all other printable ASCII.

O`.

Sort the letters together.

(.)\1*
$.&

Get the lengths of all the runs.

\$\endgroup\$
1
\$\begingroup\$

T-SQL, 168 bytes

SELECT STRING_AGG(c,'')WITHIN GROUP(ORDER BY
x)FROM(SELECT x,sum(1)c
FROM(SELECT substring(@,number,1)x FROM spt_values WHERE'P'=type)x
GROUP BY x)x WHERE x like'[a-z]'

Try it online

This will work for input fewer than 2048 characters. The output is ordered according to the position of the letter in the alphabet

\$\endgroup\$
1
\$\begingroup\$

Lua, 94 91 84 bytes

for i=65,90 do _,c=(...):upper():gsub(string.char(i),"")io.write(c~=0 and c or"")end

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Julia 1.7, 47 bytes

!x=join((c=count.('a':'z',lowercase(x)))[c.>0])

Attempt This Online!

Julia 1.0, 49 bytes

r='a':'z'
!x=join(([email protected](in((r-32)r),x))[c.>0])

Try it online!

\$\endgroup\$
1
\$\begingroup\$

K (ngn/k), 23 bytes

{,/$#'=x@<x:("a{"')__x}

Try it online!

  • _x lowercase the input
  • ("a{"')_ drop all non-letter characters
  • x@<x: sort the characters
  • #'= build a dictionary mapping the distinct characters to the number of times they appear
  • ,/$ convert the counts to strings, then join them (and implicitly return)
\$\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.