15
\$\begingroup\$

Write a program or function that takes in a string and outputs a count of each modern English alphabet letter in the string, case-insensitive.

Input: A string consisting of printable ASCII characters (code points 32-126).

Output: A list of pairs, where each pair consists of a letter and its count in the string. The list should be sorted in alphabetical order by letter. The list shall omit letters occurring zero times.

Test Cases

Input: "hello world"
Output: [('d', 1), ('e', 1), ('h', 1), ('l', 3), ('o', 2), ('r', 1), ('w', 1)]
Input: "The quick brown fox jumps over the lazy dog"
Output: [('a', 1), ('b', 1), ('c', 1), ('d', 1), ('e', 3), ('f', 1), ('g', 1), ('h', 2), ('i', 1), ('j', 1), ('k', 1), ('l', 1), ('m', 1), ('n', 1), ('o', 4), ('p', 1), ('q', 1), ('r', 2), ('s', 1), ('t', 2), ('u', 2), ('v', 1), ('w', 1), ('x', 1), ('y', 1), ('z', 1)]

Code Golf Specifics:

Your goal is to write the shortest possible code in bytes that correctly solves the problem. Your code must be able to handle any valid input within the given constraints. Note that your code should treat uppercase and lowercase letters as equivalent.

Good luck!

Kai Burghardt
1,2042 gold badges11 silver badges15 bronze badges
asked Mar 3, 2023 at 20:30
\$\endgroup\$
13
  • 4
    \$\begingroup\$ I suggest test cases involving more non-letters than just spaces. \$\endgroup\$ Commented Mar 3, 2023 at 20:42
  • 7
    \$\begingroup\$ 90% sure this is a dupe. \$\endgroup\$ Commented Mar 3, 2023 at 21:15
  • 4
    \$\begingroup\$ Is outputting a Map acceptable? \$\endgroup\$ Commented Mar 3, 2023 at 21:27
  • 5
    \$\begingroup\$ closely related \$\endgroup\$ Commented Mar 4, 2023 at 7:44
  • 8
    \$\begingroup\$ Treating uppercase and lower case letters as equivalent is IMO a signficant difference from the other challenge. I don't like either challenge personally, but the dupe target is pretty dated, with rules and format I wouldn't expect to see today and I'd prefer if that were closed as a dupe of this. \$\endgroup\$ Commented Mar 4, 2023 at 12:19

47 Answers 47

1
2
7
\$\begingroup\$

Python, 60 bytes

lambda s:{c:s.lower().count(c)for c in s.lower()if'`'<c<'{'}

Attempt This Online!

Returns a dictionary. Suggested by @JonathanAllan.

Python, 70 bytes

lambda s:sorted((c,s.lower().count(c))for c in{*s.lower()}if'`'<c<'{')

Attempt This Online!

Returns a sorted list of tuples.

Python, 75 bytes

lambda s:sorted({*zip(x:=[*filter(str.isalpha,s.lower())],map(x.count,x))})

Attempt This Online!

Returns a sorted list of tuples.

Commented

lambda s: sorted( # Define an anonymous function which takes a string, s,
 # and returns a sorted version of the following:
 (c, s.lower().count(c)) # a tuple of the character, c, and its count
 # in the lowercase version of s
 for c in {*s.lower()} # for each character, c, in the lowercase version of s uniquified
 if '`' < c < '{' ) # but only keep it if it is between the characters
 # '`' (right before 'a') and '{' (right after 'z')
 # i.e., it's alphabetic
lambda s: sorted( # Define an anonymous function which takes a string, s,
 # and returns a sorted version of the following:
 {*zip( # a uniquified version of two iterables zipped together:
 x := [*filter( # filter by
 str.isalpha, # is the character in the alphabet
 s.lower() # apply to a lowercase version of s
 )], # and store in x
 map(x.count, x) )}) # the counts of each character in x
answered Mar 4, 2023 at 11:32
\$\endgroup\$
4
  • \$\begingroup\$ OP appears to allow a dictionary as output in the comments, which would make this only \60ドル\$ with lambda s:{c:s.lower().count(c)for c in s.lower()if'`'<c<'{'}. \$\endgroup\$ Commented Mar 4, 2023 at 18:29
  • \$\begingroup\$ @JonathanAllan that wouldn't be sorted though, would it? Adding the sort would be 76 bytes \$\endgroup\$ Commented Mar 4, 2023 at 20:08
  • \$\begingroup\$ No, it wouldn't be sorted, but if they allow what was linked to then a plain dictionary is acceptable. \$\endgroup\$ Commented Mar 4, 2023 at 22:23
  • \$\begingroup\$ @JonathanAllan alright, thanks. \$\endgroup\$ Commented Mar 5, 2023 at 10:03
6
\$\begingroup\$

Vyxal, 4 bytes

ǍɽĊs

Try it Online!

How it works:

ǍɽĊs
Ǎɽ Remove non-alphabetical chars and lowercase
 Ċ Count of each element
 s Sorted 
answered Mar 3, 2023 at 20:59
\$\endgroup\$
6
\$\begingroup\$

C (gcc), (削除) 97 (削除ここまで) (削除) 94 (削除ここまで) 87 bytes

  • -3 thanks to Unrelated String
  • -7 thanks to c--

Uses uppercase as the challenge only states case-insensitive.

f(char*s){for(int a[96]={},i=64;i<90;)*s?a[*s++&95]++:a[++i]&&printf("%c:%d ",i,a[i]);}

Try it online!

Ungolfed:

f(char*s){
 for(int a[96]={},i=64;
 i<90;) // for all characters in string, then from 'A' to 'Z':
 *s? // done processing string?
 a[*s++&95]++: // no, uppercase letter and increment count
 a[++i]&&printf("%c:%d ",i,a[i]); // yes, print counts
}
answered Mar 4, 2023 at 21:28
\$\endgroup\$
1
  • \$\begingroup\$ If uppercase is allowed, 95 \$\endgroup\$ Commented Mar 5, 2023 at 5:23
5
\$\begingroup\$

jq, 66 bytes

ascii_downcase|reduce match("[a-z]";"g").string as $c({};.[$c]+=1)

Try it online!

reduce is just too good.

answered Mar 4, 2023 at 4:40
\$\endgroup\$
5
\$\begingroup\$

Java (JDK), (削除) 151 (削除ここまで) (削除) 142 (削除ここまで) 135 bytes

s->{var m=new java.util.TreeMap();for(var c:s.replaceAll("[^a-zA-Z]","").toCharArray())m.merge(c|=32,1,(a,b)->(int)a+(int)b);return m;}

Try it online!

Saved 15 bytes thanks to Kevin Cruijssen.

answered Mar 3, 2023 at 21:41
\$\endgroup\$
3
  • 1
    \$\begingroup\$ You can remove <Character,Long> and use 1,(a,b)->(int)a+(int)b instead for -7 bytes. And you can also changed the .chars().forEach(c-> with (char)c to a regular for(var c:s....toCharArray()) and c for another -2 bytes: try it online. \$\endgroup\$ Commented Mar 4, 2023 at 15:32
  • 1
    \$\begingroup\$ Oh, and -6 more bytes by using c|=32 instead of c, adding the case-insensitive flag (?i) to the regex, and removing the .toLowerCase(): try it online. :) (Relevant tip.) \$\endgroup\$ Commented Mar 4, 2023 at 15:38
  • 1
    \$\begingroup\$ @KevinCruijssen Nice, I'd forgotten about those bitwise tricks with ASCII. Actually it seems [^a-zA-Z] is shorter than (?i)[^a-z] though. \$\endgroup\$ Commented Mar 4, 2023 at 15:40
5
\$\begingroup\$

Perl 5 -n, 37 bytes

for$l(a..z){/$l/i&&say"$l ".s/$l//gi}

Try it online!

answered Mar 4, 2023 at 22:36
\$\endgroup\$
5
\$\begingroup\$

Excel, (削除) 85 (削除ここまで) 82 bytes

Saved 3 bytes thanks to JvdV

=LET(c,CHAR(ROW(65:90)),q,LEN(A1)-LEN(SUBSTITUTE(UPPER(A1),c,)),FILTER(c&"="&q,q))

The LET() function allows you to assign variables to values and reference them by name later. Every term is a pair except the last which is the output.

  • c,CHAR(ROW(65:90)) creates an array of the strings A through Z.
  • q,LEN(a)-LEN(SUBSTITUTE(UPPER(a),c,)) creates an array of how many times each letter appears by measuring the length of the input vs. the length if we replace that letter with nothing. SUBSTITUTE() is case-sensitive so we transform the input to uppercase.
  • FILTER(c&"="&q,q) combines the array of letters with the count of each character and then filter for just those where the count (q) was truthy (anything not zero).

Screenshot

answered Mar 6, 2023 at 16:10
\$\endgroup\$
2
  • 1
    \$\begingroup\$ If OP doesn't require tupples and uppercase answers are allowed, then maybe remove the 1st variable and nest it inside SUBSTITUTE(): =LET(x,CHAR(ROW(65:90)),y,LEN(A1)-LEN(SUBSTITUTE(UPPER(A1),x,)),FILTER(x&"="&y,y)) for 82 bytes. \$\endgroup\$ Commented Mar 7, 2023 at 12:27
  • 1
    \$\begingroup\$ @JvdV Good point. I usually write LET() functions for PPCG in their long form and then cut it down. I overlooked the fact that LEN() doesn't care about case so I wasn't saving bytes*2 with the variable. \$\endgroup\$ Commented Mar 7, 2023 at 14:37
5
\$\begingroup\$

PowerShell Core, 62 bytes

$args-match'[a-z]'|%{"$_"|% *l*r}|group|%{,($_.Name,$_.Count)}

Try it online!

$args-match'[a-z]' # For each character argument, exclude non letters characters
|%{"$_"|% *l*r} # Converts to lowercase
|group # Groups them
|%{,($_.Name,$_.Count)} # build pairs of letters and counts
answered Mar 7, 2023 at 0:42
\$\endgroup\$
2
  • \$\begingroup\$ Love the solution, but it's missing a sort, unfortunately. \$\endgroup\$ Commented Mar 8, 2023 at 4:04
  • \$\begingroup\$ @BrunoBrant The output seems sorted by characters already, it looks like group does it by default. Do you have a failing test case that I could try? \$\endgroup\$ Commented Mar 8, 2023 at 18:58
5
\$\begingroup\$

Pascal (FPC), (削除) 185 (削除ここまで) ... 134 bytes

var c,d:char;s:string;i:word;begin;read(s);for c:=^to^do begin;i:=0;for d in upcase(s)do i+=ord(c=d);if i>0then writeln(c,i)end;end.

Try it online! (134b, courtesy of @michael-tkach)

(削除) 150b (削除ここまで) (削除) 155b (削除ここまで) (削除) 160b (削除ここまで) (削除) 161b (削除ここまで) (削除) 162b (削除ここまで) (削除) 185b (削除ここまで)

Iterates over the alphabet and the input string s, comparing chars d and c. The for <char> in <string> syntax was handy. Implemented some of the Pascal golfing tips.

answered Mar 6, 2023 at 14:51
\$\endgroup\$
1
4
\$\begingroup\$

Mathematica (Wolfram Language), 34 bytes

KeySort@*LetterCounts@*ToLowerCase

TIO.run is in the comments below. Edited to save 4 bytes thanks to a suggestion from ZaMoC.

answered Mar 3, 2023 at 20:52
\$\endgroup\$
5
  • 1
    \$\begingroup\$ 34 bytes here you are... ;) \$\endgroup\$ Commented Mar 3, 2023 at 21:00
  • \$\begingroup\$ I just got it to work on TIO, but your answer is shorter. Thanks. \$\endgroup\$ Commented Mar 3, 2023 at 21:05
  • 1
    \$\begingroup\$ Hi, in order to avoid [] you can also use KeySort@LetterCounts@ToLowerCase@#& for 35 bytes. But in this case you can "chain" 3 functions using @* for 1 extra byte. \$\endgroup\$ Commented Mar 3, 2023 at 21:10
  • \$\begingroup\$ Yeah, I should have thought about the operator form. Thanks for your suggestion. I did that on my answer to this related question: codegolf.stackexchange.com/questions/258558/… \$\endgroup\$ Commented Mar 3, 2023 at 21:13
  • \$\begingroup\$ It's strange that LetterCounts works fine on tio.run, but WordCounts causes an error. (WordCounts is used in the answer to the question in the previous comment.) I guess WordCounts uses some NLP, but that isn't needed for just counting letters. \$\endgroup\$ Commented Mar 3, 2023 at 21:17
4
\$\begingroup\$

JavaScript (ES6), 82 bytes

Probably takes a list of pairs a bit too literally... ̄\_(ツ)_/ ̄

s=>[...s.toLowerCase()].sort().join``.match(/([a-z])1円*/g).map(s=>[s[0],s.length])

Try it online!

answered Mar 3, 2023 at 23:43
\$\endgroup\$
4
  • \$\begingroup\$ s.split(c) is not right. You take into account the case of letters when separating. Because of this for The tuick brown fox jumps over the lazy dog your function outputs only 2 t instead of 3 t \$\endgroup\$ Commented Mar 4, 2023 at 4:15
  • \$\begingroup\$ @EzioMercer You're right. Updated to a new method. \$\endgroup\$ Commented Mar 4, 2023 at 8:55
  • \$\begingroup\$ 77 bytes \$\endgroup\$ Commented Mar 4, 2023 at 13:13
  • \$\begingroup\$ @Shaggy I decided to return a list and there's already an answer using an object, so I'll stick to that. \$\endgroup\$ Commented Mar 4, 2023 at 15:20
4
\$\begingroup\$

JavaScript, 68 bytes

s=>s.toLowerCase(m={}).match(/[a-z]/g).sort().map(l=>m[l]=-~m[l])&&m

Try it:

f=s=>s.toLowerCase(m={}).match(/[a-z]/g).sort().map(l=>m[l]=-~m[l])&&m
;[
 'hello world',
 'The tuick brown fox jumps over the lazy dog'
].forEach(s=>console.log(f(s)))

UPD 73 -> 68

Thanks to Shaggy for the tips (one, two) to reduce bytes count

answered Mar 4, 2023 at 4:25
\$\endgroup\$
4
  • 4
    \$\begingroup\$ (m[l]||0)+1 can be -~m[l] \$\endgroup\$ Commented Mar 4, 2023 at 7:51
  • 4
    \$\begingroup\$ Oh, and you can initialise m within toLowerCase() to save another byte. \$\endgroup\$ Commented Mar 4, 2023 at 8:07
  • 1
    \$\begingroup\$ Actually, assigning the RegEx to m rather than using an explicit object should work, too. \$\endgroup\$ Commented Mar 4, 2023 at 13:09
  • \$\begingroup\$ @Shaggy You mean m=/[a-z]/g? \$\endgroup\$ Commented Mar 4, 2023 at 13:23
4
\$\begingroup\$

05AB1E, (削除) 9 (削除ここまで) 6 bytes

álТøê

Try it online!

Input as a list of characters.

Alternative 6 bytes answer with input as a string: (suggested by @KevinCruijssen)

ál{Åγø

Try it online!

-3 thanks to @KevinCruijssen

Explanation

á # Filter for alphabetic characters only
 lÐ # Convert to lowercase and triplicate
 ¢ # Count the occurences of each character
 øê # Zip, sort, and uniquify
á # Filter for alphabetic characters only
 l{ # Convert to lowercase and sort
 Åγ # Run-length encode the string
 ø # Zip
answered Mar 4, 2023 at 8:16
\$\endgroup\$
2
  • \$\begingroup\$ ʒa} is the builtin á. :) Also, you can remove the S by taking the input as a list of characters: try it online. Or if you prefer to keep the input as string, here is a 6 bytes alternative using the run-length encode builtin: ál{Åγø \$\endgroup\$ Commented Mar 4, 2023 at 15:24
  • \$\begingroup\$ @KevinCruijssen thanks, updated! \$\endgroup\$ Commented Mar 4, 2023 at 15:36
4
\$\begingroup\$

Ruby, 48 bytes

->s{[*s.upcase.chars.tally.slice(*?A..?Z).sort]}

Attempt This Online!

answered Mar 6, 2023 at 12:30
\$\endgroup\$
1
  • 1
    \$\begingroup\$ No need to use outer splat. ->s{s.upcase.chars.tally.slice(*?A..?Z).sort} works just fine. \$\endgroup\$ Commented May 16, 2023 at 9:09
4
\$\begingroup\$

Retina 0.8.2, (削除) 38 (削除ここまで) 29 bytes

T`Llp`ll_
O`.
(.)1円*
1,ドル $.&¶

Try it online! Output includes trailing newlines. Saved 9 bytes thank to @FryAmTheEggman. Explanation:

T`Llp`ll_

Convert letters to lower case and delete all other printable ASCII.

O`.

Sort the characters.

(.)1円*
1,ドル $.&¶

Output the count of each letter.

Previous 38-byte version worked with any input, not just printable ASCII:

T`L`l
O`.
M!`([a-z])1円*
(.)1円*
1,ドル $.&

Try it online! Explanation:

T`L`l

Lowercase the input string.

O`.

Sort the characters.

M!`([a-z])1円*

Extract the runs of identical letters.

(.)1円*
1,ドル $.&

Output the count of each letter.

(削除) 31 (削除ここまで) 30 bytes in Retina 1:

.
$L
O`.
L$`([a-z])1円*
1,ドル $.&

Try it online! Explanation:

.
$L

Lowercase the input.

O`.

Sort the characters.

L$`([a-z])1円*

For each run of identical letters...

1,ドル $.&

... output the count of each letter.

answered Mar 3, 2023 at 23:56
\$\endgroup\$
2
  • \$\begingroup\$ It seems you can save a bit by removing the bad characters instead of keeping the good ones. \$\endgroup\$ Commented Mar 7, 2023 at 4:23
  • \$\begingroup\$ Perhaps a few more by using T more. \$\endgroup\$ Commented Mar 7, 2023 at 4:25
4
\$\begingroup\$

Pip, (削除) 21 (削除ここまで) 23 bytes

YSSLCaFiUQy@XL;Pi.(iNy)

How?

YSSLCaFiUQy@XL;Pi.(iNy) : One arg; str
 a : First input
 LC : To lowercase
 SS : Sort
Y : Yank
 Fi : For i in
 UQy : Unique values of y
 @XL : Only lowercase alphabet characters
 P : Print
 i : Letter
 . : Concatenated with
 iN : Letter in
 y : Input

Try It Online!

answered Mar 6, 2023 at 16:27
\$\endgroup\$
2
  • \$\begingroup\$ This works on the current test cases, but the challenge specifies that all non-letter characters should be ignored, not just spaces. I think looping over z and adding some logic to skip letters whose count is zero will be your best bet. \$\endgroup\$ Commented Mar 16, 2023 at 18:23
  • \$\begingroup\$ @DLosc Sorry about that! This should work? Lmk if there're any more problems :) \$\endgroup\$ Commented Mar 16, 2023 at 19:38
3
\$\begingroup\$

Arturo, 34 bytes

$=>[match lower&{/\pL}|tally|sort]

Try it

answered Mar 3, 2023 at 22:23
\$\endgroup\$
3
\$\begingroup\$

Charcoal, 15 bytes

⭆1ΦEβ⟦λNo↧θλ⟧§λ1

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

 β Predefined variable lowercase alphabet
 E Map over letters
 λ Current letter
 ⟦ ⟧ Make into tuple with
 No Count of
 λ Current letter in
 θ Input string
 ↧ Lowercased
 Φ Filtered where
 §λ1 Count was nonzero
⭆1 Pretty-print
answered Mar 4, 2023 at 0:01
\$\endgroup\$
3
\$\begingroup\$

J9.4, 35 bytes

'\pL'(~.,:<@#/.~)@/:~@rxall tolower

J903, 37 bytes

'[a-z]'(~.,:<@#/.~)@/:~@rxall tolower

Attempt This Online!

Explanation is the same, but the PCRE engine was updated which makes the regex 2 bytes shorter.

'\pL'(~.,:<@#/.~)@/:~@rxall tolower
 tolower NB. lowercase the input
'\pL' rxall NB. match every letter
 /:~@ NB. then sort
 ( )@ NB. then invoke a monadic fork
 #/.~ NB. count the occurrences of each letter
 <@ NB. then box each result
 ~. NB. uniquify the matches
 ,: NB. stack matches on top of counts
answered Mar 4, 2023 at 0:11
\$\endgroup\$
3
\$\begingroup\$

Thunno, \18ドル\log_{256}(96)\approx\$ 14.82 bytes

UgAzsAqkztcsZZZUz:

Attempt This Online!

Explanation

U # Lowercase
 gAzsAqk # Alphabetic characters only
 zt # Triplicate
cs # Counts of each
 ZZ # Zip
 ZU # Uniquify
 z: # Sort
answered Mar 4, 2023 at 8:11
\$\endgroup\$
3
\$\begingroup\$

J, 32 bytes

(u:97+i.26)(e.#[;"+1#.=/)tolower

Attempt This Online!

u:97+i.26 A character vector of all lowercase letters.
tolower Input converted to lowercase.
(u:97+i.26)(...)tolower Apply inner function with lowercase alphabet as left argument and lowercased string as right argument.
=/ Equality table.
1#. Sum each row. This gives a vector of length 26 with the count of each letter in the input.
[;"+ Pair up each letter with its count.
e.# Only keep the pairs where the letter is an element of the input.

answered Mar 4, 2023 at 12:02
\$\endgroup\$
3
\$\begingroup\$

Jelly, 8 bytes

ŒlḟŒuṢŒr

Try it online!

At least slightly less boring than if I'd used Øa. Feels ever so vaguely beatable, still...

Œl The lowercased input,
 ḟŒu with elements of the uppercased input filtered out.
 ṢŒr Sort and run-length encode.
answered Mar 5, 2023 at 5:26
\$\endgroup\$
3
\$\begingroup\$

Japt v2.0a0, (削除) 15 (削除ここまで) 13 bytes

v r\L ü ËÎ+DÊ

Try it

-2 by Shaggy

Outputs a list of "ab" strings where a is the character and b is the number of occurrences

Japt, 7 bytes

ü ËÎ+DÊ

Try it

Doesn’t remove non-letters

Made on My iPhone

ü ËÎ+DÊ # input string
ü # list of same characters grouped together
 Ë # map each string of same char to:
 Î # the character
 +DÊ # append length of group
answered Mar 4, 2023 at 16:53
\$\endgroup\$
6
  • \$\begingroup\$ Note that the challenge requires the counting of letters only and that the output be sorted by character. \$\endgroup\$ Commented Mar 6, 2023 at 10:14
  • \$\begingroup\$ @Shaggy Oops, forgot to read the rules lol \$\endgroup\$ Commented Mar 6, 2023 at 12:07
  • 1
    \$\begingroup\$ 13 bytes in v2. \$\endgroup\$ Commented Mar 6, 2023 at 12:32
  • \$\begingroup\$ @Shaggy Only took you 20 seconds to golf mine! Thanks \$\endgroup\$ Commented Mar 6, 2023 at 12:36
  • \$\begingroup\$ You might be able to pass the v as an argument to ü instead to save a byte but we'll need clarification on whether the output must be lowercase or if it can be mixed case. \$\endgroup\$ Commented Mar 6, 2023 at 12:44
3
\$\begingroup\$

Common Lisp, 110 bytes

(lambda(s)(reduce(lambda(s c &aux(e(assoc c s)))(if e(prog1 s(incf(cdr e)))(acons c 1 s)))s :initial-value()))

The ungolfed version is:

(defun frequencies (string)
 (reduce (lambda (map char)
 (let ((entry (assoc char map)))
 (if entry
 (prog1 map
 (incf (cdr entry)))
 (acons char 1 map))))
 string
 :initial-value nil))

For example:

> (frequencies "abcbad")
((#\d . 1) (#\c . 1) (#\b . 2) (#\a . 2))
answered Mar 6, 2023 at 14:02
\$\endgroup\$
3
\$\begingroup\$

Pascal, (削除) 590 (削除ここまで) 358 bytes

This full program requires a processor supporting features of ISO standard 10206 "Extended Pascal". Furthermore,

  • the implementation-dependent behavior of the selection order in a for ... in set member iteration statement must be ascending,
  • the implementation-defined default TotalWidth for integer-type write arguments must be sufficiently large in order to leave some space between a character and the number, and
  • the implementation-defined set of available characters contains both upper and lowercase characters.

The GPC (GNU Pascal Compiler) fulfills these conditions on an x86‐64 Linux system if compiling with the ‐‐extended-pascal option.

program p(input,output);var c:char;f:array[char]of integer value[otherwise 0];begin while not EOF do begin read(c);c:=(c+'ABCDEFGHIJKLMNOPQRSTUVWXYZ')[index('abcdefghijklmnopqrstuvwxyz',c)+1];f[c]:=f[c]+1 end;for c in['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']do if 0<f[c]then writeLn(c,f[c])end.

Ungolfed:

program letterFrequency(input, output);
 var
 c: char;
 letterFrequency: array[char] of integer value [otherwise 0];
 begin
 while not EOF(input) do
 begin
 { `read(input, c)` is equivalent to `c := input^; get(input)`. }
 read(input, c);
 
 { There is no built-in "change case" function as Pascal does not
 guarantee the coexistence of lower and uppercase letters. The EP
 function `index(source, pattern)` returns the index of the first
 occurence of `pattern` in `source`. If `pattern` is not found,
 zero is returned. Remember, `string` indices are 1-based, thus
 add `1` to select the prepended value of `c`. }
 c := (c + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
 [index('abcdefghijklmnopqrstuvwxyz', c) + 1];
 
 letterFrequency[c] := letterFrequency[c] + 1;
 end;
 
 for c in ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] do
 begin
 if letterFrequency[c] > 0 then
 begin
 writeLn(c, letterFrequency[c]);
 end;
 end;
 end.

See also FreePascal implementation.

answered Mar 6, 2023 at 0:00
\$\endgroup\$
2
  • 1
    \$\begingroup\$ "Pascal does not guarantee that the characters 'a' through 'z' are arranged in contiguous order." — Ok, Pascal does not, but what about you? q:=Pos(c,'abcdefghijklmnopqrstuvwxyz');if q>0then c:='ABCDEFGHIJKLMNOPQRSTUVWXYZ'[q]; \$\endgroup\$ Commented Mar 6, 2023 at 4:18
  • \$\begingroup\$ @manAtWork Thanks for essentially reminding me of this golfing tip. I have adapted it to Extended Pascal, that means using the standardized index. \$\endgroup\$ Commented Mar 6, 2023 at 18:36
3
\$\begingroup\$

CJam, 19 bytes

el_'{,97>--$e`{W%}%

Try it online!

Returns strings in the form of {char}{count}

Explanation

el_'{,97>--$e`{W%}% # a function taking an input string
el_ -- # remove all elements of the input which do not occur in
 '{,97> # the character range lowercase a-z
 $ # sort
 e` # run-length encode (1h1e2l as an example)
 {W%}% # to meet the output specification of {char}{count} and not {count}{char}
 # we reverse each of the arrays in this sorted array
answered Mar 6, 2023 at 18:50
\$\endgroup\$
3
\$\begingroup\$

And any other shell that supports ${var,,} to downcase.

Bash, 35 bytes

grep -o [a-z]<<<${*,,}|sort|uniq -c

Try it online!

answered Mar 16, 2023 at 12:46
\$\endgroup\$
3
\$\begingroup\$

Haskell, (削除) 75 (削除ここまで) 71 bytes

-4 bytes thanks to Lynn

f s=[(l,n)|(u,l)<-zip['A'..'Z']['a'..],n<-[sum[1|c<-s,l==c||u==c]],n>0]

Attempt This Online!

Explanation

List comprehensions seem to be shorter than map and filter.

f s=

Define our function, f, which takes a string s.

zip['A'..'Z']['a'..]

Create a list of (uppercase letter, lowercase letter) tuples.

(u,l)<-___

For each uppercase letter u and lowercase letter l in that list...

,n<-sum[1|c<-s,l==c||u==c]

Let n be the number of characters c in s for which c equals one of l and u...

[(l,n)|____,n>0]

Return a list of tuples of l and the corresponding n where n is greater than 0.


A solution using toLower from Data.Char comes in at 76 bytes:

import Data.Char
f s=[(l,n)|l<-['a'..'z'],n<-[sum[1|c<-s,l==toLower c]],n>0]
answered Mar 16, 2023 at 19:23
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Slightly shorter is f s=[(l,n)|(u,l)<-zip['A'..'Z']['a'..],n<-[sum[1|c<-s,c==u||c==l]],n>0] \$\endgroup\$ Commented May 12, 2023 at 14:33
3
\$\begingroup\$

Julia 1.0, 51 bytes

~s=(x='A':'Z';[email protected](in(x=>x+32),s);(x.=>y)[y.>0])

Try it online!

  • Thanks to MarcMush for the following:
    1. replace sum(==(x),uppercase(s)) with sum(in(x=>x+32),s)
    2. replace Tuples with Pairs (e.g., (a,b) vs. a=>b).

54 byte solution

~s=(y='A':'Z'.|>x->x=>sum(in(x=>x+32),s))[@.last(y)>0]

Try it online!

55 byte solution

~s=[x=>y for x='A':'Z' for y=sum(in(x=>x+32),s) if y>0]

Try it online!

answered Mar 24, 2023 at 22:26
\$\endgroup\$
6
  • 1
    \$\begingroup\$ Thanks! Actually, I was including the assignment in the header, since I've seen other examples of that. I've now moved it to back to the code and updated the byte count. \$\endgroup\$ Commented Mar 27, 2023 at 13:43
  • 1
    \$\begingroup\$ This would be fine, since it is an anonymous function, and the header is just to store it, but what you did was a snippet, not a function (not valid Julia code by itself). If other answers are not valid, I try to point it out (not many people check Julia answers) \$\endgroup\$ Commented Mar 28, 2023 at 15:43
  • 1
    \$\begingroup\$ It is probably golfable further, but this works for 62 bytes \$\endgroup\$ Commented May 10, 2023 at 10:33
  • 1
    \$\begingroup\$ -6 bytes by avoiding the way too long uppercase and using Pairs instead of Tuples Try it online! \$\endgroup\$ Commented May 18, 2023 at 19:07
  • 1
    \$\begingroup\$ @MarcMush Brilliant! I can improve several of my other posts with those suggestions. I used your ideas to trim 11 bytes off my 62 byte solution, so now it's the best so far. \$\endgroup\$ Commented May 24, 2023 at 23:11
2
\$\begingroup\$

Excel (ms365), 87 bytes

enter image description here

Formula in B1:

=LET(x,CHAR(ROW(97:122)),y,LEN(A1)-LEN(SUBSTITUTE(LOWER(A1),x,)),FILTER(HSTACK(x,y),y))

And 83 bytes if you don't want tupples, but a concatenation would do:

=LET(x,CHAR(ROW(97:122)),y,LEN(A1)-LEN(SUBSTITUTE(LOWER(A1),x,)),FILTER(x&"-"&y,y))
answered Mar 7, 2023 at 12:18
\$\endgroup\$
1
2

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.