Letter frequency: Difference between revisions

From Rosetta Code
Content added Content deleted
(Add Refal)
 
(44 intermediate revisions by 26 users not shown)
Line 15: Line 15:
{{trans|Python}}
{{trans|Python}}


<lang 11l>F countletters(s)
<syntaxhighlight lang="11l">F countletters(s)
DefaultDict[Char, Int] results
DefaultDict[Char, Int] results
L(char) s
L(char) s
Line 25: Line 25:
:start:
:start:
L(letter, count) countletters(File(:argv[1]).read())
L(letter, count) countletters(File(:argv[1]).read())
print(letter‘=’count)</lang>
print(letter‘=’count)</syntaxhighlight>


{{out}}
{{out}}
Line 43: Line 43:
contained in the file.
contained in the file.


<lang 8080asm>bdos: equ 5 ; CP/M syscalls
<syntaxhighlight lang="8080asm">bdos: equ 5 ; CP/M syscalls
putch: equ 2 ; Print a character
putch: equ 2 ; Print a character
puts: equ 9 ; Print a string
puts: equ 9 ; Print a string
Line 159: Line 159:
numend: db 13,10,'$' ; a 16-bit number, plus newline.
numend: db 13,10,'$' ; a 16-bit number, plus newline.


</syntaxhighlight>
</lang>


=={{header|8th}}==
=={{header|8th}}==
<lang 8th>
<syntaxhighlight lang="8th">


needs map/iter
needs map/iter
Line 204: Line 204:
print-results
print-results
bye ;
bye ;
</syntaxhighlight>
</lang>
=={{header|AArch64 Assembly}}==
{{works with|as|Raspberry Pi 3B version Buster 64 bits <br> or android 64 bits with application Termux }}
<syntaxhighlight lang AArch64 Assembly>
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program cptletters64.s */


/************************************/
/* Constantes */
/************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
.equ BUFFERSIZE, 300000

/************************************/
/* Initialized data */
/************************************/
.data
szMessOpen: .asciz "File open error.\n"
szMessStat: .asciz "File information error.\n"
szMessRead: .asciz "File read error.\n"
szMessClose: .asciz "File close error.\n"
szMessDecryptText: .asciz "Decrypted text :\n"
szMessCryptText: .asciz "Encrypted text :\n"
szMessErrorChar: .asciz "Character text not Ok!\n"
szFileName: .asciz "unixdict.txt"
//szFileName: .asciz "test1.txt"
szMessResult: .asciz "Result: = "
szCarriageReturn: .asciz "\n"
szMessStart: .asciz "Program 64 bits start.\n"
/************************************/
/* UnInitialized data */
/************************************/
.bss
sZoneConv: .skip 24
tabCptLetters: .skip 8 * 52 // (A-Z a-z) counter array
sBuffer: .skip BUFFERSIZE // file buffer
/************************************/
/* code section */
/************************************/
.text
.global main
main: // entry of program
ldr x0,qAdrszMessStart
bl affichageMess
mov x0,AT_FDCWD
ldr x1,qAdrszFileName // file name
mov x2,#O_RDWR // flags
mov x3,#0 // mode
mov x8,#OPEN // file open
svc 0
cmp x0,#0 // error ?
ble 99f
mov x9,x0 // FD save

mov x0,x9
ldr x1,qAdrsBuffer
ldr x2,#iBufferSize
mov x8,#READ // call system read file
svc 0
cmp x0,#0 // error read ?
blt 97f
mov x6,x0 // file size
mov x0,x9
mov x8,#CLOSE // call system close file
svc 0
cmp x0,#0 // error close ?
blt 96f
ldr x0,qAdrsBuffer
mov x1,x6
bl cptLetters
b 100f
96:
ldr x0,qAdrszMessClose
bl affichageMess
mov x0,#-1 // error
b 100f
97:
ldr x0,qAdrszMessRead
bl affichageMess
mov x0,#-1 // error
b 100f
99:
ldr x0,qAdrszMessOpen
bl affichageMess
mov x0,#-1 // error

100: // standard end of the program
mov x0, #0 // return code
mov x8, #EXIT // request to exit program
svc 0 // perform the system call

qAdrsZoneConv: .quad sZoneConv
qAdrszMessResult: .quad szMessResult
qAdrszCarriageReturn: .quad szCarriageReturn
qAdrszMessStart: .quad szMessStart
qAdrszFileName: .quad szFileName
qAdrszMessOpen: .quad szMessOpen
qAdrszMessRead: .quad szMessRead
qAdrszMessStat: .quad szMessStat
qAdrszMessClose: .quad szMessClose
qAdrsBuffer: .quad sBuffer
iBufferSize: .quad BUFFERSIZE
/***************************************************/
/* letters frequency */
/***************************************************/
/* r0 contains a file buffer */
/* r1 contains string length */
cptLetters:
stp x1,lr,[sp,-16]!
stp x2,x3,[sp,-16]!
stp x4,x5,[sp,-16]!
stp x6,x7,[sp,-16]!
ldr x4,qAdrtabCptLetters // counter array
mov x3,#0 // index string
1:
ldrb w2,[x0,x3] // load byte of string
cmp x2,#'A' // select alpha characters lower or upper
blt 5f
cmp x2,#'Z'
bgt 2f
sub x5,x2,#65 // convert ascii upper in index array (0-25)
b 3f
2:
cmp x2,#'z'
bgt 5f
cmp x2,#'a'
blt 5f
sub x5,x2,#97 - 26 // convert ascii lower in index array (26,52]
3:
ldr x7,[x4,x5,lsl #3] // load counter of load character
add x7,x7,#1 // increment counter
str x7,[x4,x5,lsl #3] // and store
5:
add x3,x3,#1 // increment text index
cmp x3,x1 // end ?
blt 1b // and loop
ldr x7,qAdrszMessResult
mov x2,65 // for upper ascci character
mov x3,#0
6: // result display
ldr x1,[x4,x3,lsl #3] // load counter
cmp x1,#0 // if zero not display
beq 7f
cmp x3,#25 // upper ?
add x2,x3,65 // for upper ascci character
add x8,x3,#97 - 26 // lower
csel x6,x2,x8,le // compute ascii character
strb w6,[x7,#9] // store in message
mov x0,x1 // convert count in decimal
ldr x1,qAdrsZoneConv
bl conversion10
ldr x0,qAdrszMessResult // and display
bl affichageMess
ldr x0,qAdrsZoneConv
bl affichageMess
ldr x0,qAdrszCarriageReturn
bl affichageMess
7:
add x3,x3,#1
cmp x3,#52
blt 6b
100:
ldp x6,x7,[sp],16
ldp x4,x5,[sp],16
ldp x2,x3,[sp],16
ldp x1,lr,[sp],16 // TODO: retaur à completer
ret
qAdrtabCptLetters: .quad tabCptLetters
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeARM64.inc"

</syntaxhighlight>
{{Out}}
<pre>
Program 64 bits start.
Result: a = 16421
Result: b = 4115
Result: c = 8216
Result: d = 5799
Result: e = 20144
Result: f = 2662
Result: g = 4129
Result: h = 5208
Result: i = 13980
Result: j = 430
Result: k = 1925
Result: l = 10061
Result: m = 5828
Result: n = 12097
Result: o = 12738
Result: p = 5516
Result: q = 378
Result: r = 13436
Result: s = 10210
Result: t = 12836
Result: u = 6489
Result: v = 1902
Result: w = 1968
Result: x = 617
Result: y = 3633
Result: z = 433
</pre>
=={{header|ACL2}}==
=={{header|ACL2}}==
<lang Lisp>(defun increment-alist (tbl key)
<syntaxhighlight lang="lisp">(defun increment-alist (tbl key)
(cond ((endp tbl) (list (cons key 1)))
(cond ((endp tbl) (list (cons key 1)))
((eql (car (first tbl)) key)
((eql (car (first tbl)) key)
Line 222: Line 430:


(defun letter-freq (str)
(defun letter-freq (str)
(freq-table (coerce str 'list)))</lang>
(freq-table (coerce str 'list)))</syntaxhighlight>

=={{header|Action!}}==
{{libheader|Action! Tool Kit}}
<syntaxhighlight lang="action!">INCLUDE "D2:PRINTF.ACT" ;from the Action! Tool Kit

CARD ARRAY histogram(256)

PROC Clear()
INT i

FOR i=0 TO 255
DO histogram(i)=0 OD
RETURN

PROC ProcessLine(CHAR ARRAY line)
INT i

FOR i=1 TO line(0)
DO
histogram(line(i))==+1
OD
RETURN

PROC ProcessFile(CHAR ARRAY fname)
CHAR ARRAY line(255)
BYTE dev=[1]

Close(dev)
Open(dev,fname,4)
WHILE Eof(dev)=0
DO
InputSD(dev,line)
ProcessLine(line)
OD
Close(dev)
RETURN

PROC PrintResult()
INT i
CHAR ARRAY s(10)

FOR i=0 TO 255
DO
IF histogram(i) THEN
StrC(histogram(i),s)
PrintF(" %C:%-5S",i,s)
FI
OD
RETURN

PROC Main()
CHAR ARRAY fname="H6:LETTE_KJ.ACT"
BYTE LMARGIN=$52,old

old=LMARGIN
LMARGIN=0 ;remove left margin on the screen

Put(125) PutE() ;clear the screen
PrintF("Reading ""%S""...%E%E",fname)
ProcessFile(fname)
PrintResult()

LMARGIN=old ;restore left margin on the screen
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Letter_frequency.png Screenshot from Atari 8-bit computer]
<pre>
Reading "H6:LETTE_KJ.ACT"...

:150 !:1 ":12 $:1 %:5
(:27 ):27 +:1 ,:8 -:1
.:5 0:7 1:5 2:7 4:1
5:10 6:2 ::3 ;:4 =:13
A:25 B:2 C:19 D:12 E:16
F:10 G:4 H:8 I:13 J:1
K:2 L:9 M:5 N:15 O:20
P:16 R:44 S:4 T:20 U:6
W:1 Y:8 [:1 ]:1 _:1
a:16 c:9 d:10 e:49 f:9
g:8 h:9 i:36 l:20 m:14
n:29 o:23 p:2 r:25 s:24
t:24 u:5 v:7
</pre>


=={{header|Ada}}==
=={{header|Ada}}==


<lang Ada>with Ada.Text_IO;
<syntaxhighlight lang="ada">with Ada.Text_IO;


procedure Letter_Frequency is
procedure Letter_Frequency is
Line 245: Line 536:
end if;
end if;
end loop;
end loop;
end Letter_Frequency;</lang>
end Letter_Frequency;</syntaxhighlight>


{{out}} (counting the characters of its own source code):
{{out}} (counting the characters of its own source code):
Line 260: Line 551:


=={{header|Aikido}}==
=={{header|Aikido}}==
<lang aikido>import ctype
<syntaxhighlight lang="aikido">import ctype


var letters = new int [26]
var letters = new int [26]
Line 278: Line 569:
foreach i letters.size() {
foreach i letters.size() {
println (cast<char>('a' + i) + " " + letters[i])
println (cast<char>('a' + i) + " " + letters[i])
}</lang>
}</syntaxhighlight>


=={{header|Aime}}==
=={{header|Aime}}==
Letters proper:
Letters proper:
<lang aime>file f;
<syntaxhighlight lang="aime">file f;
index x;
index x;
integer c;
integer c;
Line 296: Line 587:
o_form("%c: /w5/\n", c, x[c] += x[c + 'a' - 'A'] += 0);
o_form("%c: /w5/\n", c, x[c] += x[c + 'a' - 'A'] += 0);
c += 1;
c += 1;
}</lang>
}</syntaxhighlight>
All chars:
All chars:
<lang aime>file f;
<syntaxhighlight lang="aime">file f;
index x;
index x;
integer c, n;
integer c, n;
Line 310: Line 601:
for (c, n in x) {
for (c, n in x) {
o_form("%c: /w5/\n", c, n);
o_form("%c: /w5/\n", c, n);
}</lang>
}</syntaxhighlight>


=={{header|ALGOL 68}}==
=={{header|ALGOL 68}}==
<lang algol68>
<syntaxhighlight lang="algol68">
BEGIN
BEGIN
[0:max abs char]INT histogram;
[0:max abs char]INT histogram;
Line 340: Line 631:
FOR i FROM ABS "a" TO ABS "z" DO printf (($a3xg(0)l$, REPR i, histogram[i])) OD
FOR i FROM ABS "a" TO ABS "z" DO printf (($a3xg(0)l$, REPR i, histogram[i])) OD
END
END
</syntaxhighlight>
</lang>
{{out}} Counting letters in its own source code:
{{out}} Counting letters in its own source code:
<pre>
<pre>
Line 367: Line 658:


=={{header|APL}}==
=={{header|APL}}==
<lang apl> freq←{(⍪∪⍵),+/(∪⍵)∘.⍷⍵}
<syntaxhighlight lang="apl"> freq←{(⍪∪⍵),+/(∪⍵)∘.⍷⍵}


freq 0 1 2 3 2 3 4 3 4 4 4
freq 0 1 2 3 2 3 4 3 4 4 4
Line 381: Line 672:
l 2
l 2
o 2
o 2
n 1</lang>
n 1</syntaxhighlight>


The above solution doesn't do the "open a text file" part of the task. File I/O is implementation-dependent, but here's how to do it in Dyalog:
The above solution doesn't do the "open a text file" part of the task. File I/O is implementation-dependent, but here's how to do it in Dyalog:


{{works with|Dyalog APL}}
{{works with|Dyalog APL}}
<lang apl> text ← ⊃⎕nget 'filename'</lang>
<syntaxhighlight lang="apl"> text ← ⊃⎕nget 'filename'</syntaxhighlight>


... after which the above <tt>freq</tt> function can be applied to <tt>text</tt>.
... after which the above <tt>freq</tt> function can be applied to <tt>text</tt>.
Line 394: Line 685:
This is probably best handled with vanilla AppleScript and ASObjC each each doing what it does best. The test text used here is the one specified for the [https://www.rosettacode.org/wiki/Word_frequency Word frequency] task.
This is probably best handled with vanilla AppleScript and ASObjC each each doing what it does best. The test text used here is the one specified for the [https://www.rosettacode.org/wiki/Word_frequency Word frequency] task.


<lang applescript>use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
<syntaxhighlight lang="applescript">use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"
use framework "Foundation"
use scripting additions
use scripting additions
Line 441: Line 732:
-- Test with the text file for the "Word frequency" task.
-- Test with the text file for the "Word frequency" task.
set theFile to ((path to desktop as text) & "135-0.txt") as alias
set theFile to ((path to desktop as text) & "135-0.txt") as alias
return letterFrequencyinFile(theFile)</lang>
return letterFrequencyinFile(theFile)</syntaxhighlight>


{{output}}
{{output}}
Line 450: Line 741:
If we just want to get something up and running (and tabulating output) with a minimum of new code –
If we just want to get something up and running (and tabulating output) with a minimum of new code –
enough to read the frequencies of shortish texts – we can quickly click together a composition of generic functions.
enough to read the frequencies of shortish texts – we can quickly click together a composition of generic functions.
<lang applescript>use AppleScript version "2.4"
<syntaxhighlight lang="applescript">use AppleScript version "2.4"
use framework "Foundation"
use framework "Foundation"
use scripting additions
use scripting additions
Line 957: Line 1,248:
set my text item delimiters to dlm
set my text item delimiters to dlm
return s
return s
end unwords</lang>
end unwords</syntaxhighlight>
{{Out}}
{{Out}}
<pre>SPACE -> 1330 p -> 138 " -> 28 k -> 5
<pre>SPACE -> 1330 p -> 138 " -> 28 k -> 5
Line 987: Line 1,278:
we can do something a little faster with a list of simple regular expressions, again composing a solution from existing generic functions.
we can do something a little faster with a list of simple regular expressions, again composing a solution from existing generic functions.


<lang applescript>use AppleScript version "2.4"
<syntaxhighlight lang="applescript">use AppleScript version "2.4"
use framework "Foundation"
use framework "Foundation"
use scripting additions
use scripting additions
Line 1,292: Line 1,583:
end tell
end tell
end if
end if
end zipWith</lang>
end zipWith</syntaxhighlight>
{{Out}}
{{Out}}
<pre>e -> 332590
<pre>e -> 332590
Line 1,320: Line 1,611:
q -> 2533
q -> 2533
z -> 1906</pre>
z -> 1906</pre>

=={{header|Applesoft BASIC}}==
<syntaxhighlight lang="gwbasic"> 100 LET F$ = "TEXT FILE"
110 LET D$ = CHR$ (4)
120 DIM C(255)
130 PRINT D$"OPEN "F$
140 FOR Q = 0 TO 1 STEP 0
150 PRINT D$"READ "F$
160 ONERR GOTO 240
170 GET C$
180 POKE 216,0
190 LET C = ASC (C$)
200 LET C(C) = C(C) + 1
210 PRINT
220 NEXT
230 STOP
240 POKE 216,0
250 LET E = PEEK (222)
260 PRINT D$"CLOSE "F$
270 IF E < > 5 THEN RESUME
280 FOR I = 0 TO 255
290 IF C(I) THEN GOSUB 320
300 NEXT I
310 END
320 IF I < 32 THEN PRINT "^" CHR$ (64 + I);
330 IF I > = 32 AND I < 128 THEN PRINT CHR$ (I);
340 IF I > 127 THEN PRINT "CHR$("I")";
350 PRINT "="C(I)" ";
360 RETURN</syntaxhighlight>
=={{header|ARM Assembly}}==
{{works with|as|Raspberry Pi <br> or android 32 bits with application Termux}}
<syntaxhighlight lang ARM Assembly>
/* ARM assembly Raspberry PI */
/* program cptletters.s */

/************************************/
/* Constantes */
/************************************/
/* for this file see task include a file in language ARM assembly*/
.include "../constantes.inc"
.equ READ, 3
.equ WRITE, 4
.equ OPEN, 5
.equ CLOSE, 6
.equ O_RDWR, 0x0002 @ open for reading and writing
.equ BUFFERSIZE, 300000
/************************************/
/* Initialized data */
/************************************/
.data
szMessOpen: .asciz "File open error.\n"
szMessStat: .asciz "File information error.\n"
szMessRead: .asciz "File read error.\n"
szMessClose: .asciz "File close error.\n"
szMessDecryptText: .asciz "Decrypted text :\n"
szMessCryptText: .asciz "Encrypted text :\n"
szMessErrorChar: .asciz "Character text not Ok!\n"
szFileName: .asciz "unixdict.txt"
//szFileName: .asciz "test1.txt"
szMessResult: .asciz "Result: = "
szCarriageReturn: .asciz "\n"
szMessStart: .asciz "Program 32 bits start.\n"
/************************************/
/* UnInitialized data */
/************************************/
.bss
sZoneConv: .skip 24
tabCptLetters: .skip 4 * 52 @ (A-Z a-z) counter array
sBuffer: .skip BUFFERSIZE @ file buffer
/************************************/
/* code section */
/************************************/
.text
.global main
main: @ entry of program
ldr r0,iAdrszMessStart
bl affichageMess
ldr r0,iAdrszFileName @ file name
mov r1,#O_RDWR @ flags
mov r2,#0 @ mode
mov r7,#OPEN @ file open
svc 0
cmp r0,#0 @ error ?
ble 99f
mov r8,r0 @ FD save

mov r0,r8
ldr r1,iAdrsBuffer
ldr r2,#iBufferSize
mov r7,#READ @ call system read file
svc 0
cmp r0,#0 @ error read ?
blt 97f
mov r6,r0 @ file size
mov r0,r8
mov r7,#CLOSE @ call system close file
svc 0
cmp r0,#0 @ error close ?
blt 96f
ldr r0,iAdrsBuffer
mov r1,r6
bl cptLetters
b 100f
96:
ldr r0,iAdrszMessClose
bl affichageMess
mov r0,#-1 @ error
b 100f
97:
ldr r0,iAdrszMessRead
bl affichageMess
mov r0,#-1 @ error
b 100f
99:
ldr r0,iAdrszMessOpen
bl affichageMess
mov r0,#-1 @ error

100: @ standard end of the program
mov r0, #0 @ return code
mov r7, #EXIT @ request to exit program
svc 0 @ perform the system call

iAdrsZoneConv: .int sZoneConv
iAdrszMessResult: .int szMessResult
iAdrszCarriageReturn: .int szCarriageReturn
iAdrszMessStart: .int szMessStart
iAdrszFileName: .int szFileName
iAdrszMessOpen: .int szMessOpen
iAdrszMessRead: .int szMessRead
iAdrszMessStat: .int szMessStat
iAdrszMessClose: .int szMessClose
iAdrsBuffer: .int sBuffer
iBufferSize: .int BUFFERSIZE
/***************************************************/
/* letters frequency */
/***************************************************/
/* r0 contains a file buffer */
/* r1 contains string length */
cptLetters:
push {r1-r7,lr} @ save registers
ldr r4,iAdrtabCptLetters @ counter array
mov r3,#0 @ index string
1:
ldrb r2,[r0,r3] @ load byte of string
cmp r2,#'A' @ select alpha characters lower or upper
blt 5f
cmp r2,#'Z'
bgt 2f
sub r5,r2,#65 @ convert ascii upper in index array (0-25)
b 3f
2:
cmp r2,#'z'
bgt 5f
cmp r2,#'a'
blt 5f
sub r5,r2,#97 - 26 @ convert ascii lower in index array (26,52]
3:
ldr r7,[r4,r5,lsl #2] @ load counter of load character
add r7,r7,#1 @ increment counter
str r7,[r4,r5,lsl #2] @ and store
5:
add r3,r3,#1 @ increment text index
cmp r3,r1 @ end ?
blt 1b @ and loop
ldr r7,iAdrszMessResult
mov r3,#0
6: @ result display
ldr r1,[r4,r3,lsl #2] @ load counter
cmp r1,#0 @ if zero not display
beq 7f
cmp r3,#25 @ upper ?
addle r6,r3,#65 @ yes compute ascci character
addgt r6,r3,#97 - 26 @ lower
strb r6,[r7,#9] @ store in message
mov r0,r1 @ convert count in decimal
ldr r1,iAdrsZoneConv
bl conversion10
ldr r0,iAdrszMessResult @ and display
bl affichageMess
ldr r0,iAdrsZoneConv
bl affichageMess
ldr r0,iAdrszCarriageReturn
bl affichageMess
7:
add r3,r3,#1
cmp r3,#52
blt 6b
100:
pop {r1-r7,pc}
iAdrtabCptLetters: .int tabCptLetters
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
/* for this file see task include a file in language ARM assembly*/
.include "../affichage.inc"

</syntaxhighlight>
{{Out}}
with the file unixdict.txt
<pre>
Program 32 bits start.
Result: a = 16421
Result: b = 4115
Result: c = 8216
Result: d = 5799
Result: e = 20144
Result: f = 2662
Result: g = 4129
Result: h = 5208
Result: i = 13980
Result: j = 430
Result: k = 1925
Result: l = 10061
Result: m = 5828
Result: n = 12097
Result: o = 12738
Result: p = 5516
Result: q = 378
Result: r = 13436
Result: s = 10210
Result: t = 12836
Result: u = 6489
Result: v = 1902
Result: w = 1968
Result: x = 617
Result: y = 3633
Result: z = 433
</pre>


=={{header|Arturo}}==
=={{header|Arturo}}==


<lang rebol>source: {
<syntaxhighlight lang="rebol">source: {
The Red Death had long devastated the country.
The Red Death had long devastated the country.
No pestilence had ever been so fatal, or so hideous.
No pestilence had ever been so fatal, or so hideous.
Line 1,335: Line 1,859:
}
}


valid: split "abcdefghijklmnopqrstuvwxyz"
valid: as.agnostic [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]
frequencies: #[]
frequencies: #[]


loop split lower source 'ch [
loop split lower source 'ch [
if in? to :literal ch valid [
if in? ch valid [
if not? key? frequencies ch ->
if not? key? frequencies ch ->
set frequencies ch 0
set frequencies ch 0
Line 1,347: Line 1,871:
]
]


inspect.muted frequencies</lang>
inspect.muted frequencies</syntaxhighlight>


{{out}}
{{out}}
Line 1,378: Line 1,902:
=={{header|AutoHotkey}}==
=={{header|AutoHotkey}}==
<br>This is the past version of this edit but made into a function, and now it only shows the letters that are in it, but not the ones with 0 letters
<br>This is the past version of this edit but made into a function, and now it only shows the letters that are in it, but not the ones with 0 letters
<lang AutoHotkey>LetterFreq(Var) {
<syntaxhighlight lang="autohotkey">LetterFreq(Var) {
Loop, 26
Loop, 26
{
{
Line 1,391: Line 1,915:
var2 := "foo bar"
var2 := "foo bar"
Msgbox, % LetterFreq(var)
Msgbox, % LetterFreq(var)
Msgbox, % LetterFreq(var2)</lang>
Msgbox, % LetterFreq(var2)</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 1,425: Line 1,949:
You can choose to use case sensitive search and if special chars should be searched too.
You can choose to use case sensitive search and if special chars should be searched too.


<lang>
<syntaxhighlight lang="text">
Func _Letter_frequency($Path, $fcase = True, $fspecial_chars = True)
Func _Letter_frequency($Path, $fcase = True, $fspecial_chars = True)
Local $hFile, $sRead, $iupto, $iStart, $iCount
Local $hFile, $sRead, $iupto, $iStart, $iCount
Line 1,451: Line 1,975:
If $iCount > 0 Then ConsoleWrite(Chr($iStart + $i) & " : " & $iCount & @CRLF)
If $iCount > 0 Then ConsoleWrite(Chr($iStart + $i) & " : " & $iCount & @CRLF)
Next
Next
EndFunc ;==>_Letter_frequency</lang>
EndFunc ;==>_Letter_frequency</syntaxhighlight>


{{out}}
{{out}}
Line 1,467: Line 1,991:


=={{header|AWK}}==
=={{header|AWK}}==
<syntaxhighlight lang="awk">
<lang AWK>
# usage: awk -f letters.awk HolyBible.txt
# usage: awk -f letters.awk HolyBible.txt


Line 1,473: Line 1,997:
{ for(i=1;i<=NF;i++) m[$i]++}
{ for(i=1;i<=NF;i++) m[$i]++}
END { for(i in m) printf("%9d %-14s\n", m[i],i) }
END { for(i in m) printf("%9d %-14s\n", m[i],i) }
</syntaxhighlight>
</lang>


=={{header|BaCon}}==
=={{header|BaCon}}==
<lang freebasic>txt$ = LOAD$("bible.txt")
<syntaxhighlight lang="freebasic">txt$ = LOAD$("bible.txt")


FOR x = 97 TO 122
FOR x = 97 TO 122
PRINT CHR$(x-32), " ", CHR$(x), " : ", COUNT(txt$, x-32), " - ", COUNT(txt$, x)
PRINT CHR$(x-32), " ", CHR$(x), " : ", COUNT(txt$, x-32), " - ", COUNT(txt$, x)
NEXT
NEXT
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 1,513: Line 2,037:


=={{header|BBC BASIC}}==
=={{header|BBC BASIC}}==
<lang bbcbasic> DIM cnt%(255)
<syntaxhighlight lang="bbcbasic"> DIM cnt%(255)
file% = OPENIN("C:\unixdict.txt")
file% = OPENIN("C:\unixdict.txt")
Line 1,531: Line 2,055:
FOR c% = &41 TO &5A
FOR c% = &41 TO &5A
PRINT CHR$(c%)CHR$(c%+32) ": " cnt%(c%)+cnt%(c%+32)
PRINT CHR$(c%)CHR$(c%+32) ": " cnt%(c%)+cnt%(c%+32)
NEXT</lang>
NEXT</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 1,563: Line 2,087:


=={{header|BCPL}}==
=={{header|BCPL}}==
<lang bcpl>get "libhdr"
<syntaxhighlight lang="bcpl">get "libhdr"


let start() be
let start() be
Line 1,584: Line 2,108:
endread()
endread()
$)</lang>
$)</syntaxhighlight>
{{out}}
{{out}}
<pre>Aa: 16421
<pre>Aa: 16421
Line 1,612: Line 2,136:
Yy: 3633
Yy: 3633
Zz: 433</pre>
Zz: 433</pre>

=={{header|BQN}}==
<code>"sample.txt"</code> can be substituted with any filename.
<syntaxhighlight lang="bqn">Freq←⍷≍/⁼∘⊐

Freq "balloon"
# For a file:
Freq •FLines "sample.txt"</syntaxhighlight>
<syntaxhighlight lang="text">┌─
╵ 'b' 'a' 'l' 'o' 'n'
1 1 2 2 1
┘</syntaxhighlight>


=={{header|Bracmat}}==
=={{header|Bracmat}}==
<lang bracmat>(lc=
<syntaxhighlight lang="bracmat">(lc=
counts c
counts c
. fil$(!arg,r) {open file for reading}
. fil$(!arg,r) {open file for reading}
Line 1,631: Line 2,167:


lc$"valid.bra" {example: count letters in Bracmat's validation suite.}
lc$"valid.bra" {example: count letters in Bracmat's validation suite.}
</syntaxhighlight>
</lang>
<lang bracmat>107*A
<syntaxhighlight lang="bracmat">107*A
+ 33*B
+ 33*B
+ 37*C
+ 37*C
Line 1,682: Line 2,218:
+ 685*y
+ 685*y
+ 211*z
+ 211*z
+ 1035*i</lang>
+ 1035*i</syntaxhighlight>


=={{header|C}}==
=={{header|C}}==
<lang c>/* declare array */
<syntaxhighlight lang="c">/* declare array */
int frequency[26];
int frequency[26];
int ch;
int ch;
Line 1,703: Line 2,239:
else if ('A' <= ch && ch <= 'Z') /* upper case */
else if ('A' <= ch && ch <= 'Z') /* upper case */
frequency[ch-'A']++;
frequency[ch-'A']++;
}</lang>
}</syntaxhighlight>


=={{header|C sharp}}==
=={{header|C sharp}}==
<lang csharp>using System;
<syntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.IO;
Line 1,742: Line 2,278:
}
}
}
}
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre> : 1
<pre> : 1
Line 1,757: Line 2,293:
Declarative approach:
Declarative approach:


<lang csharp>
<syntaxhighlight lang="csharp">
var freq = from c in str
var freq = from c in str
where char.IsLetter(c)
where char.IsLetter(c)
Line 1,766: Line 2,302:
foreach(var g in freq)
foreach(var g in freq)
Console.WriteLine(g);
Console.WriteLine(g);
</syntaxhighlight>
</lang>
<pre>
<pre>
C:2
C:2
Line 1,779: Line 2,315:


=={{header|C++}}==
=={{header|C++}}==
<lang cpp>#include <fstream>
<syntaxhighlight lang="cpp">#include <fstream>
#include <iostream>
#include <iostream>


Line 1,804: Line 2,340:
}
}
}
}
}</lang>
}</syntaxhighlight>
{{out}} when file contains "Hello, world!" (without quotes):
{{out}} when file contains "Hello, world!" (without quotes):
<pre>
<pre>
Line 1,819: Line 2,355:


=={{header|Clojure}}==
=={{header|Clojure}}==
<lang Clojure>(println (sort-by second >
<syntaxhighlight lang="clojure">(println (sort-by second >
(frequencies (map #(java.lang.Character/toUpperCase %)
(frequencies (map #(java.lang.Character/toUpperCase %)
(filter #(java.lang.Character/isLetter %) (slurp "text.txt"))))))</lang>
(filter #(java.lang.Character/isLetter %) (slurp "text.txt"))))))</syntaxhighlight>


=={{header|Common Lisp}}==
=={{header|Common Lisp}}==
<lang lisp>(defun letter-freq (file)
<syntaxhighlight lang="lisp">(defun letter-freq (file)
(with-open-file (stream file)
(with-open-file (stream file)
(let ((str (make-string (file-length stream)))
(let ((str (make-string (file-length stream)))
Line 1,835: Line 2,371:
(if (zerop (rem i 8)) #\newline #\tab))))))
(if (zerop (rem i 8)) #\newline #\tab))))))


(letter-freq "test.lisp")</lang>
(letter-freq "test.lisp")</syntaxhighlight>

=={{header|COBOL}}==
<syntaxhighlight lang="cobol">
IDENTIFICATION DIVISION.
PROGRAM-ID. Letter-Frequency.
AUTHOR. Bill Gunshannon.
INSTALLATION. Home.
DATE-WRITTEN. 12 December 2021.
************************************************************
** Program Abstract:
** A rather simplistic program to do the kind of thing
** that COBOL does really well.
************************************************************
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT Text-File ASSIGN TO "File.txt"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD Text-File
DATA RECORD IS Record-Name.
01 Record-Name PIC X(80).
WORKING-STORAGE SECTION.
01 Eof PIC X VALUE 'F'.

01 Letter-cnt.
05 A-cnt PIC 9(5) VALUE 0.
05 B-cnt PIC 9(5) VALUE 0.
05 C-cnt PIC 9(5) VALUE 0.
05 D-cnt PIC 9(5) VALUE 0.
05 E-cnt PIC 9(5) VALUE 0.
05 F-cnt PIC 9(5) VALUE 0.
05 G-cnt PIC 9(5) VALUE 0.
05 H-cnt PIC 9(5) VALUE 0.
05 I-cnt PIC 9(5) VALUE 0.
05 J-cnt PIC 9(5) VALUE 0.
05 K-cnt PIC 9(5) VALUE 0.
05 L-cnt PIC 9(5) VALUE 0.
05 M-cnt PIC 9(5) VALUE 0.
05 N-cnt PIC 9(5) VALUE 0.
05 O-cnt PIC 9(5) VALUE 0.
05 P-cnt PIC 9(5) VALUE 0.
05 Q-cnt PIC 9(5) VALUE 0.
05 R-cnt PIC 9(5) VALUE 0.
05 S-cnt PIC 9(5) VALUE 0.
05 T-cnt PIC 9(5) VALUE 0.
05 U-cnt PIC 9(5) VALUE 0.
05 V-cnt PIC 9(5) VALUE 0.
05 W-cnt PIC 9(5) VALUE 0.
05 X-cnt PIC 9(5) VALUE 0.
05 Y-cnt PIC 9(5) VALUE 0.
05 Z-cnt PIC 9(5) VALUE 0.
01 Letter-disp.
05 A-cnt PIC ZZZZ9.
05 B-cnt PIC ZZZZ9.
05 C-cnt PIC ZZZZ9.
05 D-cnt PIC ZZZZ9.
05 E-cnt PIC ZZZZ9.
05 F-cnt PIC ZZZZ9.
05 G-cnt PIC ZZZZ9.
05 H-cnt PIC ZZZZ9.
05 I-cnt PIC ZZZZ9.
05 J-cnt PIC ZZZZ9.
05 K-cnt PIC ZZZZ9.
05 L-cnt PIC ZZZZ9.
05 M-cnt PIC ZZZZ9.
05 N-cnt PIC ZZZZ9.
05 O-cnt PIC ZZZZ9.
05 P-cnt PIC ZZZZ9.
05 Q-cnt PIC ZZZZ9.
05 R-cnt PIC ZZZZ9.
05 S-cnt PIC ZZZZ9.
05 T-cnt PIC ZZZZ9.
05 U-cnt PIC ZZZZ9.
05 V-cnt PIC ZZZZ9.
05 W-cnt PIC ZZZZ9.
05 X-cnt PIC ZZZZ9.
05 Y-cnt PIC ZZZZ9.
05 Z-cnt PIC ZZZZ9.
PROCEDURE DIVISION.
Main-Program.
OPEN INPUT Text-File
PERFORM UNTIL Eof = 'T'
READ Text-File
AT END MOVE 'T' to Eof
END-READ
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING A-cnt OF Letter-cnt FOR ALL 'A'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING B-cnt OF Letter-cnt FOR ALL 'B'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING C-cnt OF Letter-cnt FOR ALL 'C'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING D-cnt OF Letter-cnt FOR ALL 'D'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING E-cnt OF Letter-cnt FOR ALL 'E'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING F-cnt OF Letter-cnt FOR ALL 'F'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING G-cnt OF Letter-cnt FOR ALL 'G'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING H-cnt OF Letter-cnt FOR ALL 'H'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING I-cnt OF Letter-cnt FOR ALL 'I'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING J-cnt OF Letter-cnt FOR ALL 'J'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING K-cnt OF Letter-cnt FOR ALL 'K'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING L-cnt OF Letter-cnt FOR ALL 'L'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING M-cnt OF Letter-cnt FOR ALL 'M'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING N-cnt OF Letter-cnt FOR ALL 'N'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING O-cnt OF Letter-cnt FOR ALL 'O'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING P-cnt OF Letter-cnt FOR ALL 'P'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING Q-cnt OF Letter-cnt FOR ALL 'Q'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING R-cnt OF Letter-cnt FOR ALL 'R'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING S-cnt OF Letter-cnt FOR ALL 'S'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING T-cnt OF Letter-cnt FOR ALL 'T'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING U-cnt OF Letter-cnt FOR ALL 'U'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING V-cnt OF Letter-cnt FOR ALL 'V'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING W-cnt OF Letter-cnt FOR ALL 'W'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING X-cnt OF Letter-cnt FOR ALL 'X'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING Y-cnt OF Letter-cnt FOR ALL 'Y'
INSPECT FUNCTION UPPER-CASE(Record-Name)
TALLYING Z-cnt OF Letter-cnt FOR ALL 'Z'
END-PERFORM.
CLOSE Text-File.
MOVE CORRESPONDING Letter-cnt To Letter-disp.
DISPLAY 'Letter Frequency Distribution'.
DISPLAY '-----------------------------'.
DISPLAY 'A : ' A-cnt OF Letter-disp ' '
'N : ' N-cnt OF Letter-disp.
DISPLAY 'B : ' B-cnt OF Letter-disp ' '
'O : ' O-cnt OF Letter-disp.
DISPLAY 'C : ' C-cnt OF Letter-disp ' '
'P : ' P-cnt OF Letter-disp.
DISPLAY 'D : ' D-cnt OF Letter-disp ' '
'Q : ' Q-cnt OF Letter-disp.
DISPLAY 'E : ' E-cnt OF Letter-disp ' '
'R : ' R-cnt OF Letter-disp.
DISPLAY 'F : ' F-cnt OF Letter-disp ' '
'S : ' S-cnt OF Letter-disp.
DISPLAY 'G : ' G-cnt OF Letter-disp ' '
'T : ' T-cnt OF Letter-disp.
DISPLAY 'H : ' H-cnt OF Letter-disp ' '
'U : ' U-cnt OF Letter-disp.
DISPLAY 'I : ' I-cnt OF Letter-disp ' '
'V : ' V-cnt OF Letter-disp.
DISPLAY 'J : ' J-cnt OF Letter-disp ' '
'W : ' W-cnt OF Letter-disp.
DISPLAY 'K : ' K-cnt OF Letter-disp ' '
'X : ' X-cnt OF Letter-disp.
DISPLAY 'L : ' L-cnt OF Letter-disp ' '
'Y : ' Y-cnt OF Letter-disp.
DISPLAY 'M : ' M-cnt OF Letter-disp ' '
'Z : ' Z-cnt OF Letter-disp.
STOP RUN.
END-PROGRAM.
</syntaxhighlight>

{{out}}

<pre>
Letter Frequency Distribution
-----------------------------
A : 416 N : 434
B : 120 O : 545
C : 316 P : 215
D : 267 Q : 12
E : 679 R : 436
F : 122 S : 432
G : 171 T : 493
H : 131 U : 180
I : 429 V : 57
J : 12 W : 97
K : 17 X : 35
L : 303 Y : 50
M : 162 Z : 60
</pre>


=={{header|Component Pascal}}==
=={{header|Component Pascal}}==
BlackBox Component Builder
BlackBox Component Builder
<lang oberon2>
<syntaxhighlight lang="oberon2">
MODULE LetterFrecuency;
MODULE LetterFrecuency;
IMPORT Files,StdLog,Strings;
IMPORT Files,StdLog,Strings;
Line 1,884: Line 2,626:
END Do;
END Do;
END LetterFrecuency.
END LetterFrecuency.
</syntaxhighlight>
</lang>
Execute: ^Q LetterFrecuency.Do<br/>
Execute: ^Q LetterFrecuency.Do<br/>
{{out}}
{{out}}
Line 1,917: Line 2,659:


=={{header|Cowgol}}==
=={{header|Cowgol}}==
<lang cowgol>include "cowgol.coh";
<syntaxhighlight lang="cowgol">include "cowgol.coh";
include "argv.coh";
include "argv.coh";
include "file.coh";
include "file.coh";
Line 1,962: Line 2,704:
print_nl();
print_nl();
ch := ch + 1;
ch := ch + 1;
end loop;</lang>
end loop;</syntaxhighlight>


{{out}}
{{out}}
Line 1,996: Line 2,738:


=={{header|D}}==
=={{header|D}}==
<lang d>void main() {
<syntaxhighlight lang="d">void main() {
import std.stdio, std.ascii, std.algorithm, std.range;
import std.stdio, std.ascii, std.algorithm, std.range;


Line 2,006: Line 2,748:


writefln("%(%(%s, %),\n%)", frequency[].chunks(10));
writefln("%(%(%s, %),\n%)", frequency[].chunks(10));
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>16421, 4115, 8216, 5799, 20144, 2662, 4129, 5208, 13980, 430,
<pre>16421, 4115, 8216, 5799, 20144, 2662, 4129, 5208, 13980, 430,
Line 2,014: Line 2,756:
=={{header|Delphi}}==
=={{header|Delphi}}==
See [https://www.rosettacode.org/wiki/Letter_frequency#Pascal Pascal].
See [https://www.rosettacode.org/wiki/Letter_frequency#Pascal Pascal].

=={{header|Draco}}==
<syntaxhighlight lang="draco">proc nonrec main() void:
file() infile;
[256] char linebuf;
[256] word count;
*char line;
char c;
byte i;
word n;
channel input text filech;
channel input text linech;
for i from 0 upto 255 do count[i] := 0 od;
line := &linebuf[0];
open(filech, infile, "unixdict.txt");
while readln(filech; line) do
open(linech, line);
while read(linech; c) do
i := pretend(c, byte);
count[i] := count[i] + 1
od;
close(linech)
od;
close(filech);
for c from 'A' upto 'Z' do
i := pretend(c, byte);
n := count[i] + count[i | 32];
writeln(c, pretend(i | 32, char), ": ", n:5)
od
corp</syntaxhighlight>
{{out}}
<pre>Aa: 16421
Bb: 4115
Cc: 8216
Dd: 5799
Ee: 20144
Ff: 2662
Gg: 4129
Hh: 5208
Ii: 13980
Jj: 430
Kk: 1925
Ll: 10061
Mm: 5828
Nn: 12097
Oo: 12738
Pp: 5516
Qq: 378
Rr: 13436
Ss: 10210
Tt: 12836
Uu: 6489
Vv: 1902
Ww: 1968
Xx: 617
Yy: 3633
Zz: 433</pre>

=={{header|EasyLang}}==
<syntaxhighlight lang="easylang">
len d[] 26
repeat
s$ = input
until s$ = ""
for c$ in strchars s$
c = strcode c$
if c >= 97 and c <= 122
c -= 32
.
if c >= 65 and c <= 91
d[c - 64] += 1
.
.
.
for i to 26
write strchar (96 + i) & ": "
print d[i]
.
input_data
Open a text file and count the occurrences of each letter.
Some of these programs count all characters (including
punctuation), but some only count letters A to Z.
Other tasks related to string operations:
</syntaxhighlight>



=={{header|EchoLisp}}==
=={{header|EchoLisp}}==
We use a property list - plist for short - which is a hash table, to store the pairs ( letter . count) .
We use a property list - plist for short - which is a hash table, to store the pairs ( letter . count) .
<lang lisp>
<syntaxhighlight lang="lisp">
;; bump count when letter added
;; bump count when letter added
(define (hash-counter hash key )
(define (hash-counter hash key )
Line 2,029: Line 2,859:
(map (curry hash-counter hash) (string->list string))
(map (curry hash-counter hash) (string->list string))
(list-sort hash-compare (symbol-plist hash)))
(list-sort hash-compare (symbol-plist hash)))
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<lang lisp>
<syntaxhighlight lang="lisp">
(define (file-stats file string)
(define (file-stats file string)
(set-plist! 'file-stats null) ; reset counters
(set-plist! 'file-stats null) ; reset counters
Line 2,056: Line 2,886:
➛ Total letters: 212631
➛ Total letters: 212631
➛ Total lines: 4539
➛ Total lines: 4539
</syntaxhighlight>
</lang>


=={{header|Eiffel}}==
=={{header|Eiffel}}==


<lang Eiffel>class
<syntaxhighlight lang="eiffel">class
APPLICATION
APPLICATION


Line 2,100: Line 2,930:
end
end
end
end
end</lang>
end</syntaxhighlight>
{{out}} when file contains "Hello, Eiffel world!":
{{out}} when file contains "Hello, Eiffel world!":
<pre>H: 1
<pre>H: 1
Line 2,114: Line 2,944:


=={{header|Elixir}}==
=={{header|Elixir}}==
<lang elixir>file = hd(System.argv)
<syntaxhighlight lang="elixir">file = hd(System.argv)


File.read!(file)
File.read!(file)
Line 2,122: Line 2,952:
|> Enum.reduce(Map.new, fn c,acc -> Map.update(acc, c, 1, &(&1+1)) end)
|> Enum.reduce(Map.new, fn c,acc -> Map.update(acc, c, 1, &(&1+1)) end)
|> Enum.sort_by(fn {_k,v} -> -v end)
|> Enum.sort_by(fn {_k,v} -> -v end)
|> Enum.each(fn {k,v} -> IO.puts "#{k} #{v}" end)</lang>
|> Enum.each(fn {k,v} -> IO.puts "#{k} #{v}" end)</syntaxhighlight>


{{out}}
{{out}}
Line 2,154: Line 2,984:
Q 378
Q 378
</pre>
</pre>

=={{header|Emacs Lisp}}==
<syntaxhighlight lang="lisp">
(defun tally-letter-frequency-in-file ()
"Open a file and count the number of times each letter appears."
(let ((alphabet "abcdefghijklmnopqrstuvwxyz") ; variable to hold letters we will be counting
(current-letter) ; variable to hold current letter we will be counting
(count) ; variable to count how many times current letter appears
(case-fold-search t)) ; ignores case
(find-file "~/Documents/Elisp/MobyDick.txt") ; open file in a buffer (or switch to buffer if file is already open)
(while (>= (length alphabet) 1) ; as long as there is at least 1 letter left in alphabet
(beginning-of-buffer) ; go to the beginning of the buffer
(setq current-letter (substring alphabet 0 1)) ; set current-letter to first letter of alphabet
(setq count (how-many current-letter)) ; count how many of this letter in file
(end-of-buffer) ; go to the end of the buffer
(insert (format "\n%s%s - %7d" current-letter (upcase current-letter) count)) ; write how many times that letter appears
(setq alphabet (substring alphabet 1 nil))) ; remove first letter from alphabet
(insert "\n")))

</syntaxhighlight>
{{out}}
<pre>

aA - 79220
bB - 17203
cC - 23318
dD - 38834
eE - 119345
fF - 21252
gG - 21287
hH - 63769
iI - 66671
jJ - 1176
kK - 8228
lL - 43349
mM - 23626
nN - 66778
oO - 70808
pP - 17873
qQ - 1581
rR - 53589
sS - 65136
tT - 89874
uU - 27205
vV - 8724
wW - 22556
xX - 1064
yY - 17242
zZ - 635
</pre>



=={{header|Erlang}}==
=={{header|Erlang}}==
<lang erlang>%% Implemented by Arjun Sunel
<syntaxhighlight lang="erlang">%% Implemented by Arjun Sunel
-module(letter_frequency).
-module(letter_frequency).
-export([main/0, letter_freq/1]).
-export([main/0, letter_freq/1]).
Line 2,185: Line 3,066:
end
end
end, lists:seq(0, 222)).
end, lists:seq(0, 222)).
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>"\n" : 5
<pre>"\n" : 5
Line 2,209: Line 3,090:


Alternatively letter_freq/1 above can be replaced with
Alternatively letter_freq/1 above can be replaced with
<syntaxhighlight lang="erlang">
<lang Erlang>
letter_freq( Data ) ->
letter_freq( Data ) ->
Dict = lists:foldl( fun (Char, Dict) -> dict:update_counter( Char, 1, Dict ) end, dict:new(), Data ),
Dict = lists:foldl( fun (Char, Dict) -> dict:update_counter( Char, 1, Dict ) end, dict:new(), Data ),
[io:fwrite( "~p : ~p~n", [[X], dict:fetch(X, Dict)]) || X <- dict:fetch_keys(Dict)].
[io:fwrite( "~p : ~p~n", [[X], dict:fetch(X, Dict)]) || X <- dict:fetch_keys(Dict)].
</syntaxhighlight>
</lang>


=={{header|ERRE}}==
=={{header|ERRE}}==
Using ERRE help file for testing.
Using ERRE help file for testing.
<lang ERRE>PROGRAM LETTER
<syntaxhighlight lang="erre">PROGRAM LETTER


DIM CNT[255]
DIM CNT[255]
Line 2,242: Line 3,123:


END PROGRAM
END PROGRAM
</syntaxhighlight>
</lang>


=={{header|Euphoria}}==
=={{header|Euphoria}}==
{{works with|OpenEuphoria}}
{{works with|OpenEuphoria}}
<lang euphoria>
<syntaxhighlight lang="euphoria">
-- LetterFrequency.ex
-- LetterFrequency.ex
-- Count frequency of each letter in own source code.
-- Count frequency of each letter in own source code.
Line 2,271: Line 3,152:


if getc(0) then end if
if getc(0) then end if
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 2,284: Line 3,165:


=={{header|F_Sharp|F#}}==
=={{header|F_Sharp|F#}}==
<lang fsharp>let alphabet =
<syntaxhighlight lang="fsharp">let alphabet =
['A'..'Z'] |> Set.ofList
['A'..'Z'] |> Set.ofList


Line 2,298: Line 3,179:


for (letter, freq) in res do
for (letter, freq) in res do
printfn "%A, %A" letter freq</lang>
printfn "%A, %A" letter freq</syntaxhighlight>


=={{header|Factor}}==
=={{header|Factor}}==
<lang factor>USING: hashtables locals io assocs kernel io.encodings.utf8 io.files formatting ;
<syntaxhighlight lang="factor">USING: hashtables locals io assocs kernel io.encodings.utf8 io.files formatting ;
IN: count-letters
IN: count-letters


Line 2,319: Line 3,200:
utf8 [ count-from-stream ] with-file-reader
utf8 [ count-from-stream ] with-file-reader
print-counts ;
print-counts ;
</syntaxhighlight>
</lang>


=={{header|FBSL}}==
=={{header|FBSL}}==
The result of the first evaluation of ASC() is retained in the symbol ASC for later use. This is a standard feature of FBSL functions. The ascii array is dynamic. Command(1) is the name of the script file.
The result of the first evaluation of ASC() is retained in the symbol ASC for later use. This is a standard feature of FBSL functions. The ascii array is dynamic. Command(1) is the name of the script file.


<lang qbasic>#APPTYPE CONSOLE
<syntaxhighlight lang="qbasic">#APPTYPE CONSOLE


'Open a text file and count the occurrences of each letter.
'Open a text file and count the occurrences of each letter.
Line 2,346: Line 3,227:


PAUSE
PAUSE
</syntaxhighlight>
</lang>


=={{header|Forth}}==
=={{header|Forth}}==
<lang forth>create counts 26 cells allot
<syntaxhighlight lang="forth">create counts 26 cells allot


: freq ( filename -- )
: freq ( filename -- )
Line 2,365: Line 3,246:
loop ;
loop ;


s" example.txt" freq</lang>
s" example.txt" freq</syntaxhighlight>


=={{header|Fortran}}==
=={{header|Fortran}}==
Using the configuration file (which has changed since the example was documented) of the J example, compilation and output of this program on a gnu/linux system is
Using the configuration file (which has changed since the example was documented) of the J example, compilation and output of this program on a gnu/linux system is
<lang fortran>
<syntaxhighlight lang="fortran">
-*- mode: compilation; default-directory: "/tmp/" -*-
-*- mode: compilation; default-directory: "/tmp/" -*-
Compilation started at Sat May 18 18:09:46
Compilation started at Sat May 18 18:09:46
Line 2,378: Line 3,259:


Compilation finished at Sat May 18 18:09:46
Compilation finished at Sat May 18 18:09:46
</syntaxhighlight>
</lang>
And here's the FORTRAN90 program source. The program reads stdin and writes the result to stdout. Future enhancement: use block size records.
And here's the FORTRAN90 program source. The program reads stdin and writes the result to stdout. Future enhancement: use block size records.
<syntaxhighlight lang="fortran">
<lang FORTRAN>
! count letters from stdin
! count letters from stdin
program LetterFrequency
program LetterFrequency
Line 2,408: Line 3,289:
write(6, *) a
write(6, *) a
end program LetterFrequency
end program LetterFrequency
</syntaxhighlight>
</lang>


=={{header|FreeBASIC}}==
=={{header|FreeBASIC}}==
<lang freebasic>' FB 1.05.0 Win64
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64


Dim a(65 to 90) As Integer ' array to hold frequency of each letter, all elements zero initially
Dim a(65 to 90) As Integer ' array to hold frequency of each letter, all elements zero initially
Line 2,438: Line 3,319:
Print
Print
Print "Press any key to quit"
Print "Press any key to quit"
Sleep</lang>
Sleep</syntaxhighlight>


{{out}}
{{out}}
Line 2,488: Line 3,369:
ecosystems on the planet. Combine that reliability with zero cost of entry and you have the perfect solution for a desktop platform.
ecosystems on the planet. Combine that reliability with zero cost of entry and you have the perfect solution for a desktop platform.
</pre>
</pre>

=={{header|Frink}}==
This example shows some of the subtle and non-obvious power of Frink in processing text files in a language-aware and Unicode-aware fashion:
* Frink has a Unicode-aware function, <CODE>graphemeList[''str'']</CODE>, which intelligently enumerates through what a human would consider to be a single visible character, including "characters" composed of multiple Unicode codepoints.
* The file fetched from Project Gutenberg is supposed to be encoded in UTF-8 character encoding, but their servers incorrectly send either that it is Windows-1252 encoded or send no character encoding at all, so this program fixes that.
* Frink has a Unicode-aware lowercase function, <CODE>lc[''str'']</CODE> that correctly handles accented characters and may even make a string longer.

* This uses full Unicode tables to determine what is a "letter."

* This works with high Unicode characters, that is above \uFFFF.

* Frink can normalize Unicode characters with its <CODE>normalizeUnicode</CODE> function so the same grapheme encoded two different ways in Unicode can be treated consistently. For example, a Unicode string can use various methods to encode what is essentially the same character/glyph. For example, the character <CODE>ô</CODE> can be represented as either <CODE>"\u00F4"</CODE> or <CODE>"\u006F\u0302"</CODE>. The former is a "precomposed" character, <CODE>"LATIN SMALL LETTER O WITH CIRCUMFLEX"</CODE>, and the latter is two Unicode codepoints, an <CODE>o</CODE> (<CODE>LATIN SMALL LETTER O</CODE>) followed by <CODE>"COMBINING CIRCUMFLEX ACCENT"</CODE>. (This is usually referred to as a "decomposed" representation.) Unicode normalization rules can convert these "equivalent" encodings into a canonical representation. This makes two different strings which look equivalent to a human (but are very different in their codepoints) be treated as the same to a computer, and these programs will count them the same. Even if the Project Gutenberg document uses precomposed and decomposed representations for the same characters, this program will fix it and count them the same! See the [[http://unicode.org/reports/tr15/ Unicode Normal Forms]] specification for more about these normalization rules. Frink implements all of them (NFC, NFD, NFKC, NFKD). NFC is the default in <CODE>normalizeUnicode[''str'', ''encoding=NFC'']</CODE>. They're interesting!

How many other languages in this page do all or any of this correctly?
<syntaxhighlight lang="frink">print[formatTable[countToArray[select[graphemeList[lc[normalizeUnicode[read["https://www.gutenberg.org/files/135/135-0.txt", "UTF-8"],"NFC"]]], %r/[[:alpha:]]/ ]] , "right"]]</syntaxhighlight>
{{out}}
<pre>
e 330603
t 235571
a 207101
o 184385
h 176823
i 175320
n 169922
s 162043
r 148632
d 108724
l 99567
u 68295
c 67332
m 62212
w 56507
f 56187
g 48543
p 43366
y 39183
b 37461
v 26258
k 14427
j 5838
x 4026
q 2533
z 1905
é 1473
è 299
æ 116
ê 74
à 64
â 56
ç 50
ü 39
î 39
œ 38
ô 34
ù 18
ï 18
û 9
ë 5
ñ 2
</pre>

=={{header|FutureBasic}}==
A clone of the Objective-C solution.

This code assumes a text file named "MyTextFile.txt" is in the same folder as the code file.
<syntaxhighlight lang="futurebasic">include "NSLog.incl"
include resources "MyTextFile.txt"

void local fn DoIt
CFURLRef url
CFStringRef string
NSUInteger length, index
unichar chr
CountedSetRef set
CFNumberRef number
url = fn BundleURLForResource( fn BundleMain, @"MyTextFile", @"txt", NULL )
string = fn StringWithContentsOfURL( url, NSUTF8StringEncoding, NULL )
if ( string )
set = fn CountedSetWithCapacity(0)
length = len(string)
for index = 0 to length - 1
chr = fn StringCharacterAtIndex( string, index )
CountedSetAddObject( set, @(chr) )
next
for number in set
NSLog(@"%C = %ld",intVal(number),fn CountedSetCountForObject( set, number ))
next
end if
end fn

fn DoIt

HandleEvents</syntaxhighlight>


=={{header|Gambas}}==
=={{header|Gambas}}==
<lang gambas>Public Sub Form_Open()
<syntaxhighlight lang="gambas">Public Sub Form_Open()
Dim sData As String = File.Load("data.txt")
Dim sData As String = File.Load("data.txt")
Dim iCount, iSpaces, iLetters, iOther As Integer
Dim iCount, iSpaces, iLetters, iOther As Integer
Line 2,510: Line 3,488:
Message("Text contains " & Len(sData) & " characters\n" & iLetters & " Letters\n" & iSpaces & " Spaces\n" & iOther & " Punctuation, newlines etc.")
Message("Text contains " & Len(sData) & " characters\n" & iLetters & " Letters\n" & iSpaces & " Spaces\n" & iOther & " Punctuation, newlines etc.")


End</lang>
End</syntaxhighlight>
Output:
Output:
<pre>
<pre>
Line 2,520: Line 3,498:


=={{header|Go}}==
=={{header|Go}}==
<lang go>package main
<syntaxhighlight lang="go">package main


import (
import (
Line 2,576: Line 3,554:
func (lfs lfList) Swap(i, j int) {
func (lfs lfList) Swap(i, j int) {
lfs[i], lfs[j] = lfs[j], lfs[i]
lfs[i], lfs[j] = lfs[j], lfs[i]
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 2,624: Line 3,602:


=={{header|Groovy}}==
=={{header|Groovy}}==
<lang groovy>def frequency = { it.inject([:]) { map, value -> map[value] = (map[value] ?: 0) + 1; map } }
<syntaxhighlight lang="groovy">def frequency = { it.inject([:]) { map, value -> map[value] = (map[value] ?: 0) + 1; map } }


frequency(new File('frequency.groovy').text).each { key, value ->
frequency(new File('frequency.groovy').text).each { key, value ->
println "'$key': $value"
println "'$key': $value"
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>'d': 1
<pre>'d': 1
Line 2,646: Line 3,624:


=={{header|Harbour}}==
=={{header|Harbour}}==
<lang visualfoxpro>PROCEDURE Main()
<syntaxhighlight lang="visualfoxpro">PROCEDURE Main()
LOCAL s := hb_MemoRead( Left( __FILE__ , At( ".", __FILE__ )) +"prg")
LOCAL s := hb_MemoRead( Left( __FILE__ , At( ".", __FILE__ )) +"prg")
LOCAL c, n, i
LOCAL c, n, i
Line 2,669: Line 3,647:
END
END


RETURN</lang>
RETURN</syntaxhighlight>


{{Out}} (counting the printable characters of its own source code):
{{Out}} (counting the printable characters of its own source code):
Line 2,681: Line 3,659:
=={{header|Haskell}}==
=={{header|Haskell}}==
Short version:
Short version:
<lang Haskell>import Data.List (group,sort)
<syntaxhighlight lang="haskell">import Data.List (group, sort)

import Control.Arrow ((&&&))
main :: IO ()
main = interact (show . map (head &&& length) . group . sort)</lang>
main = interact (show . fmap ((,) . head <*> length) . group . sort</syntaxhighlight>


or, as an alternative to sorting and grouping the whole string, we could use some kind of container as the accumulator for a single fold, for example:
or, as an alternative to sorting and grouping the whole string, we could use some kind of container as the accumulator for a single fold, for example:


<lang haskell>import Data.List (sortBy)
<syntaxhighlight lang="haskell">import Data.List (sortBy)
import qualified Data.Map.Strict as M
import qualified Data.Map.Strict as M
import Data.Ord (comparing)
import Data.Ord (comparing)
Line 2,704: Line 3,683:
(flip $ comparing snd)
(flip $ comparing snd)
. M.toList
. M.toList
. charCounts</lang>
. charCounts</syntaxhighlight>
{{Out}}
{{Out}}
<pre>(' ',516452)
<pre>(' ',516452)
Line 2,829: Line 3,808:
=={{header|Icon}} and {{header|Unicon}}==
=={{header|Icon}} and {{header|Unicon}}==
The example below counts (case insensitive) letters and was run on a version of this source file.
The example below counts (case insensitive) letters and was run on a version of this source file.
<lang Icon>link printf
<syntaxhighlight lang="icon">link printf


procedure main(A)
procedure main(A)
Line 2,849: Line 3,828:
every c := key(T) do
every c := key(T) do
printf("%s - %d\n",c,T[c])
printf("%s - %d\n",c,T[c])
end</lang>
end</syntaxhighlight>


{{libheader|Icon Programming Library}}
{{libheader|Icon Programming Library}}
Line 2,876: Line 3,855:
n - 28
n - 28
v - 4</pre>
v - 4</pre>

=={{header|Insitux}}==
Works with the Node REPL.
<syntaxhighlight lang="insitux">
(-> (read "README.md")
(filter letter?)
(map upper-case)
freqs
(sort-by 1)
reverse
(map (join " "))
(join " "))
</syntaxhighlight>
{{out}}
<pre>
E 2637 T 2238 R 1893 A 1880 N 1717 I 1676 O 1562 S 1469 L 1156 C 961 U 905 H 699 D 680 P 585 M 567 F 561 G 378 B 373 V 343 Y 324 X 263 W 220 K 134 Z 56 J 49 Q 18
</pre>


=={{header|IS-BASIC}}==
=={{header|IS-BASIC}}==
<lang IS-BASIC>100 PROGRAM "Letters.bas"
<syntaxhighlight lang="is-basic">100 PROGRAM "Letters.bas"
110 NUMERIC LETT(65 TO 90)
110 NUMERIC LETT(65 TO 90)
120 FOR I=65 TO 90
120 FOR I=65 TO 90
Line 2,899: Line 3,895:
290 CLOSE #1
290 CLOSE #1
300 CONTINUE
300 CONTINUE
310 END HANDLER</lang>
310 END HANDLER</syntaxhighlight>


=={{header|J}}==
=={{header|J}}==
<br>Input is a directory-path with filename. Result is 26 integers representing counts of each letter, in alphabetic order (a's count is first).
<br>Input is a directory-path with filename. Result is 26 integers representing counts of each letter, in alphabetic order (a's count is first).


<lang j>ltrfreq=: 3 : 0
<syntaxhighlight lang="j">ltrfreq=: 3 : 0
letters=. u: 65 + i.26 NB. upper case letters
letters=. u: 65 + i.26 NB. upper case letters
<: #/.~ letters (, -. -.~) toupper fread y
<: #/.~ letters (, -. -.~) toupper fread y
)</lang>
)</syntaxhighlight>


Example use (based on [[Read_a_configuration_file|a configuration file from another task]]):
Example use (based on [[Read_a_configuration_file|a configuration file from another task]]):


<lang j> ltrfreq 'config.file'
<syntaxhighlight lang="j"> ltrfreq 'config.file'
88 17 17 24 79 18 19 19 66 0 2 26 26 57 54 31 1 53 43 59 19 6 2 0 8 0</lang>
88 17 17 24 79 18 19 19 66 0 2 26 26 57 54 31 1 53 43 59 19 6 2 0 8 0</syntaxhighlight>


=={{header|Java}}==
=={{header|Java}}==
This implementation will capture the frequency of all characters
<syntaxhighlight lang="java5">
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
</syntaxhighlight>
<syntaxhighlight lang="java5">
public static void main(String[] args) throws IOException {
Map<Integer, Integer> frequencies = frequencies("src/LetterFrequency.java");
System.out.println(print(frequencies));
}

static String print(Map<Integer, Integer> frequencies) {
StringBuilder string = new StringBuilder();
int key;
for (Map.Entry<Integer, Integer> entry : frequencies.entrySet()) {
key = entry.getKey();
string.append("%,-8d".formatted(entry.getValue()));
/* display the hexadecimal value for non-printable characters */
if ((key >= 0 && key < 32) || key == 127) {
string.append("%02x%n".formatted(key));
} else {
string.append("%s%n".formatted((char) key));
}
}
return string.toString();
}

static Map<Integer, Integer> frequencies(String path) throws IOException {
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(path))) {
/* key = character, and value = occurrences */
Map<Integer, Integer> map = new HashMap<>();
int value;
while ((value = reader.read()) != -1) {
if (map.containsKey(value)) {
map.put(value, map.get(value) + 1);
} else {
map.put(value, 1);
}
}
return map;
}
}
</syntaxhighlight>
<pre>
44 0a
463
1 !
8 "
5 %
2 &
33 (
33 )
4 *
1 +
9 ,
3 -
29 .
5 /
2 0
4 1
3 2
1 3
1 7
1 8
1 :
19 ;
7 <
12 =
7 >
2 B
4 E
4 F
2 H
18 I
2 K
2 L
8 M
3 O
3 R
13 S
1 V
1 [
1 ]
73 a
3 b
28 c
19 d
121 e
13 f
25 g
11 h
53 i
6 j
8 k
25 l
22 m
67 n
24 o
44 p
8 q
81 r
30 s
87 t
34 u
15 v
7 w
5 x
20 y
11 {
2 |
11 }
</pre>
<br />
{{works with|Java|5+}}
{{works with|Java|5+}}
<lang java5>import java.io.BufferedReader;
<syntaxhighlight lang="java5">import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.IOException;
Line 2,941: Line 4,053:
System.out.println(Arrays.toString(countLetters("filename.txt")));
System.out.println(Arrays.toString(countLetters("filename.txt")));
}
}
}</lang>
}</syntaxhighlight>
{{works with|Java|7+}}
{{works with|Java|7+}}
In Java 7, we can use try with resources. The <code>countLetters</code> method would look like this:
In Java 7, we can use try with resources. The <code>countLetters</code> method would look like this:
<lang java5>public static int[] countLetters(String filename) throws IOException{
<syntaxhighlight lang="java5">public static int[] countLetters(String filename) throws IOException{
int[] freqs = new int[26];
int[] freqs = new int[26];
try(BufferedReader in = new BufferedReader(new FileReader(filename))){
try(BufferedReader in = new BufferedReader(new FileReader(filename))){
Line 2,958: Line 4,070:
}
}
return freqs;
return freqs;
}</lang>
}</syntaxhighlight>
{{works with|Java|8+}}
{{works with|Java|8+}}
In Java 8, we can use streams. This code also handles unicode codepoints as well. The <code>countLetters</code> method would look like this:
In Java 8, we can use streams. This code also handles unicode codepoints as well. The <code>countLetters</code> method would look like this:
<lang java5>public static Map<Integer, Long> countLetters(String filename) throws IOException {
<syntaxhighlight lang="java5">public static Map<Integer, Long> countLetters(String filename) throws IOException {
return Files.lines(Paths.get(filename))
return Files.lines(Paths.get(filename))
.flatMapToInt(String::chars)
.flatMapToInt(String::chars)
Line 2,967: Line 4,079:
.boxed()
.boxed()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}</lang>
}</syntaxhighlight>


=={{header|JavaScript}}==
=={{header|JavaScript}}==
Line 2,975: Line 4,087:
we can still use core JavasScript (ES5 in the example below), to count the characters in a text once it has been read from a file system.
we can still use core JavasScript (ES5 in the example below), to count the characters in a text once it has been read from a file system.


<lang JavaScript>(function(txt) {
<syntaxhighlight lang="javascript">(function(txt) {


var cs = txt.split(''),
var cs = txt.split(''),
Line 3,003: Line 4,115:
with a large party. Nothing could be more delightful! To be fond of\
with a large party. Nothing could be more delightful! To be fond of\
dancing was a certain step towards falling in love; and very lively\
dancing was a certain step towards falling in love; and very lively\
hopes of Mr. Bingley's heart were entertained."); </lang>
hopes of Mr. Bingley's heart were entertained."); </syntaxhighlight>


{{Out}}
{{Out}}


<lang JavaScript>[[" ", 121], ["!", 1], ["'", 1], [",", 13], ["-", 3], [".", 9], [";", 2],
<syntaxhighlight lang="javascript">[[" ", 121], ["!", 1], ["'", 1], [",", 13], ["-", 3], [".", 9], [";", 2],
["B", 3], ["H", 2], ["L", 2], ["M", 3], ["N", 2], ["S", 1], ["T", 2], ["W", 1],
["B", 3], ["H", 2], ["L", 2], ["M", 3], ["N", 2], ["S", 1], ["T", 2], ["W", 1],
["a", 53], ["b", 13], ["c", 17], ["d", 29], ["e", 82], ["f", 17], ["g", 16], ["h", 36],
["a", 53], ["b", 13], ["c", 17], ["d", 29], ["e", 82], ["f", 17], ["g", 16], ["h", 36],
["i", 44], ["j", 1], ["k", 3], ["l", 34], ["m", 11], ["n", 41], ["o", 40], ["p", 8],
["i", 44], ["j", 1], ["k", 3], ["l", 34], ["m", 11], ["n", 41], ["o", 40], ["p", 8],
["q", 2], ["r", 35], ["s", 39], ["t", 55], ["u", 20], ["v", 7], ["w", 17], ["x", 2], ["y", 16]]</lang>
["q", 2], ["r", 35], ["s", 39], ["t", 55], ["u", 20], ["v", 7], ["w", 17], ["x", 2], ["y", 16]]</syntaxhighlight>


===ES6===
===ES6===
Line 3,017: Line 4,129:
Using the 'JavaScript for Automation' embedding of a JSContext on macOS, for access to the file system:
Using the 'JavaScript for Automation' embedding of a JSContext on macOS, for access to the file system:


<lang javascript>(() => {
<syntaxhighlight lang="javascript">(() => {
'use strict';
'use strict';


Line 3,145: Line 4,257:
// MAIN ---
// MAIN ---
return main();
return main();
})();</lang>
})();</syntaxhighlight>
{{Out}}
{{Out}}
<pre>[" ",516452]
<pre>[" ",516452]
Line 3,179: Line 4,291:
["A",7359]
["A",7359]
["œ",7121]
["œ",7121]
["",7033]
["",7033]
["H",6605]
["H",6605]
["M",6208]
["M",6208]
Line 3,272: Line 4,384:
(note that this version omits the opening of a text file which is specified in the task description):
(note that this version omits the opening of a text file which is specified in the task description):


<lang javascript>(() => {
<syntaxhighlight lang="javascript">(() => {
'use strict';
'use strict';


Line 3,290: Line 4,402:
null, 2
null, 2
);
);
})();</lang>
})();</syntaxhighlight>


Using the spread operator, you get the unicode characters rather than the UTF-16 code units.
Using the spread operator, you get the unicode characters rather than the UTF-16 code units.
Line 3,322: Line 4,434:


=={{header|jq}}==
=={{header|jq}}==
The following program will report the frequency of all characters in the input file, including newlines, returns, etc, provided the file will fit in memory.<lang jq>
The following program will report the frequency of all characters in the input file, including newlines, returns, etc, provided the file will fit in memory.<syntaxhighlight lang="jq">
# Input: an array of strings.
# Input: an array of strings.
# Output: an object with the strings as keys,
# Output: an object with the strings as keys,
Line 3,333: Line 4,445:
| keys | sort[] | [., $counter[.] ]
| keys | sort[] | [., $counter[.] ]


</syntaxhighlight>
</lang>
Example:<lang sh>jq -s -R -c -f Letter_frequency.jq somefile.txt</lang>
Example:<syntaxhighlight lang="sh">jq -s -R -c -f Letter_frequency.jq somefile.txt</syntaxhighlight>
{{Out}}
{{Out}}
<pre>["\n",12]
<pre>["\n",12]
Line 3,354: Line 4,466:


=={{header|Julia}}==
=={{header|Julia}}==
<lang julia>using DataStructures
<syntaxhighlight lang="julia">using DataStructures
function letterfreq(file::AbstractString; fltr::Function=(_) -> true)
function letterfreq(file::AbstractString; fltr::Function=(_) -> true)
Line 3,361: Line 4,473:
display(letterfreq("src/Letter_frequency.jl"; fltr=isletter))
display(letterfreq("src/Letter_frequency.jl"; fltr=isletter))
</lang>{{out}}
</syntaxhighlight>{{out}}
<pre>
<pre>
DataStructures.OrderedDict{Char,Int64} with 29 entries:
DataStructures.OrderedDict{Char,Int64} with 29 entries:
Line 3,387: Line 4,499:


=={{header|K}}==
=={{header|K}}==
<lang K>+(?a;#:'=a:,/0:`)</lang>
<syntaxhighlight lang="k">+(?a;#:'=a:,/0:`)</syntaxhighlight>


Example: The file "hello.txt" contains the string "Hello, world!"
Example: The file "hello.txt" contains the string "Hello, world!"


<lang K>
<syntaxhighlight lang="k">
c:+(?a;#:'=a:,/0:`hello.txt)
c:+(?a;#:'=a:,/0:`hello.txt)
</syntaxhighlight>
</lang>


{{out}}
{{out}}
Line 3,411: Line 4,523:
Sort on decreasing occurrences:
Sort on decreasing occurrences:


<syntaxhighlight lang="k">
<lang K>
c@>c[;1]
c@>c[;1]
</syntaxhighlight>
</lang>


{{out}}
{{out}}
Line 3,430: Line 4,542:


=={{header|Kotlin}}==
=={{header|Kotlin}}==
<lang scala>// version 1.1.2
<syntaxhighlight lang="scala">// version 1.1.2


import java.io.File
import java.io.File
Line 3,440: Line 4,552:
val sum = letterMap.values.sumBy { it.size }
val sum = letterMap.values.sumBy { it.size }
println("\nTotal letters = $sum")
println("\nTotal letters = $sum")
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 3,476: Line 4,588:


Total letters = 64
Total letters = 64
</pre>

=={{header|Ksh}}==
<syntaxhighlight lang="ksh">
#!/bin/ksh

# Count the occurrences of each character

######
# main #
######

typeset -iA freqCnt
while read; do
for ((i=0; i<${#REPLY}; i++)); do
(( freqCnt[${REPLY:i:1}]++ ))
done
done < $0 ## Count chars of this code file

for ch in "${!freqCnt[@]}"; do
[[ ${ch} == ?(\S) ]] && print -- "${ch} ${freqCnt[${ch}]}"
done
</syntaxhighlight>
{{out}}
Counts the characters of the source code file
<pre>
! 2
" 4
# 19
$ 8
& 2
( 5
) 5
+ 4
- 3
/ 2
0 2
1 1
: 2
; 5
< 2
= 3
? 1
@ 1
A 1
C 6
E 2
L 2
P 2
R 2
S 1
Y 2
[ 5
] 5
a 6
b 1
c 12
d 8
e 18
f 9
h 11
i 12
k 1
l 2
m 1
n 14
o 14
p 2
q 4
r 13
s 5
t 12
u 3
w 1
y 1
{ 7
</pre>
</pre>


Line 3,482: Line 4,670:
In this entry we choose to show how lambdatalk can use any existing javascript code (say the #Javascript entry in this page), and build an interface to use it as a standard lambdatalk function. So, applied to any string the W.frequency primitive returns a pair structure containing the array of chars and the corresponding array of frequencies.
In this entry we choose to show how lambdatalk can use any existing javascript code (say the #Javascript entry in this page), and build an interface to use it as a standard lambdatalk function. So, applied to any string the W.frequency primitive returns a pair structure containing the array of chars and the corresponding array of frequencies.


<syntaxhighlight lang="scheme">
<lang Scheme>


{script
{script
Line 3,536: Line 4,724:




</syntaxhighlight>
</lang>


=={{header|langur}}==
=={{header|langur}}==
<syntaxhighlight lang="langur">val .countLetters = fn(.s) {
{{works with|langur|0.7.0}}
<lang langur>val .countLetters = f(.s) {
for[=h{}] .s2 in split(replace(.s, RE/\P{L}/)) {
for[=h{}] .s2 in split(replace(.s, RE/\P{L}/)) {
_for[.s2; 0] += 1
_for[.s2; 0] += 1
Line 3,547: Line 4,734:


val .counts = .countLetters(readfile "./fuzz.txt")
val .counts = .countLetters(readfile "./fuzz.txt")
writeln join "\n", map f(.k) $"\.k;: \.counts[.k];", keys .counts</lang>
writeln join "\n", map fn(.k) $"\.k;: \.counts[.k];", keys .counts
</syntaxhighlight>


{{out}}
{{out}}
Line 3,572: Line 4,760:


=={{header|Lasso}}==
=={{header|Lasso}}==
<lang Lasso>local(
<syntaxhighlight lang="lasso">local(
str = 'Hello world!',
str = 'Hello world!',
freq = map
freq = map
Line 3,595: Line 4,783:
with elem in #freq->keys do => {^
with elem in #freq->keys do => {^
'"'+#elem+'": '+#freq->find(#elem)+'\r'
'"'+#elem+'": '+#freq->find(#elem)+'\r'
^}</lang>
^}</syntaxhighlight>


=={{header|Liberty BASIC}}==
=={{header|Liberty BASIC}}==
Un-rem a line to convert to all-upper-case.
Un-rem a line to convert to all-upper-case.
Letter freq'y is printed as percentages.
Letter freq'y is printed as percentages.
<syntaxhighlight lang="lb">
<lang lb>
open "text.txt" for input as #i
open "text.txt" for input as #i
txt$ =input$( #i, lof( #i))
txt$ =input$( #i, lof( #i))
Line 3,621: Line 4,809:


end
end
</syntaxhighlight>
</lang>


=={{header|Lua}}==
=={{header|Lua}}==
This solution counts letters only, which could be changed by altering the pattern argument to 'gmatch' on line 31. It also treats upper and lower case letters as distinct, which could be changed by changing everything to upper or lower case with string.upper() or string.lower() before tallying.
This solution counts letters only, which could be changed by altering the pattern argument to 'gmatch' on line 31. It also treats upper and lower case letters as distinct, which could be changed by changing everything to upper or lower case with string.upper() or string.lower() before tallying.
<lang lua>-- Return entire contents of named file
<syntaxhighlight lang="lua">-- Return entire contents of named file
function readFile (filename)
function readFile (filename)
local file = assert(io.open(filename, "r"))
local file = assert(io.open(filename, "r"))
Line 3,655: Line 4,843:
-- Main procedure
-- Main procedure
local letterCount = tally()
local letterCount = tally()
for letter in readFile(arg[1]):gmatch("%a") do
for letter in readFile(arg[1] or arg[0]):gmatch("%a") do
letterCount(letter)
letterCount(letter)
end
end
for k, v in pairs(letterCount()) do
for k, v in pairs(letterCount()) do
print(k, v)
print(k, v)
end</lang>
end</syntaxhighlight>
Output from running this script on itself:
Output from running this script on itself:
<pre>i 24
<pre>i 24
g 2
h 4
e 61
f 16
f 16
c 19
d 17
R 2
R 2
o 31
p 7
m 4
n 42
k 4
l 40
y 4
w 1
x 7
u 18
v 2
v 2
c 19
k 4
M 1
s 14
s 14
d 17
l 40
e 61
t 54
t 54
a 24
m 4
r 34
u 18
C 3
C 3
M 1
o 32
A 1
A 1
g 3
x 7
F 2
F 2
r 32</pre>
y 4
w 1
n 42
h 4
a 25
p 7</pre>


=={{header|M2000 Interpreter}}==
=={{header|M2000 Interpreter}}==
<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
document file1$={Open a text file and count the occurrences of each letter.
document file1$={Open a text file and count the occurrences of each letter.
Some of these programs count all characters (including punctuation), but some only count letters A to Z
Some of these programs count all characters (including punctuation), but some only count letters A to Z
Line 3,716: Line 4,904:
print #Console, Export$
print #Console, Export$
clipboard Export$
clipboard Export$
</syntaxhighlight>
</lang>


{{out}}
{{out}}
Line 3,744: Line 4,932:


=={{header|Maple}}==
=={{header|Maple}}==
<lang Maple>StringTools:-CharacterFrequencies(readbytes("File.txt",infinity,TEXT))</lang>
<syntaxhighlight lang="maple">StringTools:-CharacterFrequencies(readbytes("File.txt",infinity,TEXT))</syntaxhighlight>


=={{header|Mathematica}} / {{header|Wolfram Language}}==
=={{header|Mathematica}} / {{header|Wolfram Language}}==


<lang Mathematica>Tally[Characters[Import["file.txt","Text"]]]</lang>
<syntaxhighlight lang="mathematica">Tally[Characters[Import["file.txt","Text"]]]</syntaxhighlight>


=={{header|MATLAB}} / {{header|Octave}}==
=={{header|MATLAB}} / {{header|Octave}}==
<lang MATLAB>function u = letter_frequency(t)
<syntaxhighlight lang="matlab">function u = letter_frequency(t)
if ischar(t)
if ischar(t)
t = abs(t);
t = abs(t);
Line 3,757: Line 4,945:
A = sparse(t+1,1,1,256,1);
A = sparse(t+1,1,1,256,1);
printf('"%c":%i\n',[find(A)-1,A(A>0)]')
printf('"%c":%i\n',[find(A)-1,A(A>0)]')
end</lang>
end</syntaxhighlight>


=={{header|Nanoquery}}==
=={{header|Nanoquery}}==
<lang Nanoquery>// define a list to hold characters and amounts
<syntaxhighlight lang="nanoquery">// define a list to hold characters and amounts
characters = list()
characters = list()
amounts = list()
amounts = list()
Line 3,797: Line 4,985:
for i in range(0, len(characters) - 1)
for i in range(0, len(characters) - 1)
println format("%-20s %d", characters[i], amounts[i])
println format("%-20s %d", characters[i], amounts[i])
end for</lang>
end for</syntaxhighlight>
{{out}}
{{out}}
<pre>$ java -jar ../nanoquery-2.3_1462.jar -b letterfreq.nq sherlock-holmes.txt
<pre>$ java -jar ../nanoquery-2.3_1462.jar -b letterfreq.nq sherlock-holmes.txt
Line 3,841: Line 5,029:
=={{header|NetRexx}}==
=={{header|NetRexx}}==
{{trans|REXX}}
{{trans|REXX}}
<lang netrexx>/* NetRexx ************************************************************
<syntaxhighlight lang="netrexx">/* NetRexx ************************************************************
* 22.05.2013 Walter Pachl translated from REXX
* 22.05.2013 Walter Pachl translated from REXX
**********************************************************************/
**********************************************************************/
Line 3,920: Line 5,108:
end
end


return fileLines</lang>
return fileLines</syntaxhighlight>


=={{header|Nim}}==
=={{header|Nim}}==
<lang nim>import tables, os
<syntaxhighlight lang="nim">import tables, os


var t = initCountTable[char]()
var t = initCountTable[char]()
Line 3,929: Line 5,117:
for c in l:
for c in l:
t.inc(c)
t.inc(c)
echo t</lang>
echo t</syntaxhighlight>


=={{header|Objeck}}==
=={{header|Objeck}}==
<lang objeck>
<syntaxhighlight lang="objeck">
use IO;
use IO;


Line 3,963: Line 5,151:
}
}
}
}
</syntaxhighlight>
</lang>


=={{header|Objective-C}}==
=={{header|Objective-C}}==


<lang objc>#import <Foundation/Foundation.h>
<syntaxhighlight lang="objc">#import <Foundation/Foundation.h>


int main (int argc, const char *argv[]) {
int main (int argc, const char *argv[]) {
Line 3,987: Line 5,175:
}
}
return 0;
return 0;
}</lang>
}</syntaxhighlight>


=={{header|OCaml}}==
=={{header|OCaml}}==
Line 3,993: Line 5,181:
We open a text file and compute letter frequency. Other characters than [a-z] and [A-Z] are ignored, and upper case letters are first converted to lower case before to compute letter frequency.
We open a text file and compute letter frequency. Other characters than [a-z] and [A-Z] are ignored, and upper case letters are first converted to lower case before to compute letter frequency.


<lang ocaml>let () =
<syntaxhighlight lang="ocaml">let () =
let ic = open_in Sys.argv.(1) in
let ic = open_in Sys.argv.(1) in
let base = int_of_char 'a' in
let base = int_of_char 'a' in
Line 4,007: Line 5,195:
for i=0 to 25 do
for i=0 to 25 do
Printf.printf "%c -> %d\n" (char_of_int(i + base)) arr.(i)
Printf.printf "%c -> %d\n" (char_of_int(i + base)) arr.(i)
done</lang>
done</syntaxhighlight>


If we want to compute all characters in an UTF8 file, we must use an external library, for example Batteries. The following function takes as input a string that contains the path to the file, and prints all the characters together with their frequencies, ordered by increasing frequencies, on the standard output.
If we want to compute all characters in an UTF8 file, we must use an external library, for example Batteries. The following function takes as input a string that contains the path to the file, and prints all the characters together with their frequencies, ordered by increasing frequencies, on the standard output.


<lang ocaml>
<syntaxhighlight lang="ocaml">
open Batteries
open Batteries


Line 4,022: Line 5,210:
@@ List.sort (fun (_,v) (_,v') -> compare v v')
@@ List.sort (fun (_,v) (_,v') -> compare v v')
@@ Hashtbl.fold (fun k v l -> (Text.of_uchar k,v) :: l) freq []
@@ Hashtbl.fold (fun k v l -> (Text.of_uchar k,v) :: l) freq []
</syntaxhighlight>
</lang>


=={{header|Ol}}==
=={{header|Ol}}==
<lang scheme>
<syntaxhighlight lang="scheme">
(define source (bytes->string (file->bytestream "letter_frequency.scm"))) ; utf-8
(define source (bytes->string (file->bytestream "letter_frequency.scm"))) ; utf-8
(define dict (lfold (lambda (ff char)
(define dict (lfold (lambda (ff char)
Line 4,051: Line 5,239:
(print))
(print))
(ff->alist dict))
(ff->alist dict))
</syntaxhighlight>
</lang>
{{Out}}
{{Out}}
<pre>NEWLINE --> 27
<pre>NEWLINE --> 27
Line 4,116: Line 5,304:


=={{header|OxygenBasic}}==
=={{header|OxygenBasic}}==
<lang oxygenbasic>
<syntaxhighlight lang="oxygenbasic">
indexbase 0
indexbase 0


Line 4,138: Line 5,326:
print pr
print pr
'putfile "CharCount.txt",pr
'putfile "CharCount.txt",pr
</syntaxhighlight>
</lang>


=={{header|PARI/GP}}==
=={{header|PARI/GP}}==
<lang parigp>v=vector(26);
<syntaxhighlight lang="parigp">v=vector(26);
U=readvec("foo.txt");
U=readvec("foo.txt");
for(i=1,#U,u=Vecsmall(U[i]);for(j=1,#u,if(u[j]>64&&u[j]<91,v[u[j]-64]++,u[j]>96&&u[j]<123,v[u[j]-96]++)));
for(i=1,#U,u=Vecsmall(U[i]);for(j=1,#u,if(u[j]>64&&u[j]<91,v[u[j]-64]++,u[j]>96&&u[j]<123,v[u[j]-96]++)));
v</lang>
v</syntaxhighlight>


=={{header|Pascal}}==
=={{header|Pascal}}==
{{works with|Extended Pascal}}
<lang pascal>program letterFrequency(input, output, stdErr);
<syntaxhighlight lang="pascal">program letterFrequency(input, output);
var
var
chart: array[char] of integer;
chart: array[char] of 0..maxInt value [otherwise 0];
c: char;
c: char;
begin
begin
{ parameter-less EOF checks for EOF(input) }
for c := low(chart) to high(chart) do
while not EOF do
begin
chart[c] := 0;
end;
// parameter-less EOF() checks for EOF(input)
while not EOF() do
begin
begin
read(c);
read(c);
inc(chart[c]);
chart[c] := chart[c] + 1
end;
end;
// now, chart[someLetter] gives you the letter’s frequency
{ now, chart[someLetter] gives you the letter’s frequency }
end.</lang>
end.</syntaxhighlight>


=={{header|Perl}}==
=={{header|Perl}}==
Counts letters in files given on command line or piped to stdin. Case insensitive.
Counts letters in files given on command line or piped to stdin. Case insensitive.
<lang perl>while (<>) { $cnt{lc chop}++ while length }
<syntaxhighlight lang="perl">while (<>) { $cnt{lc chop}++ while length }
print "$_: ", $cnt{$_}//0, "\n" for 'a' .. 'z';</lang>
print "$_: ", $cnt{$_}//0, "\n" for 'a' .. 'z';</syntaxhighlight>


=={{header|Phix}}==
=={{header|Phix}}==
<del>Counts own source or supplied filename</del> Now counts words in unixdict.txt of 17 letters or more (to make it js compatible)
<del>Counts own source or supplied filename</del> Now counts words in unixdict.txt of 17 letters or more (to make it js compatible)
<!--<lang Phix>(phixonline)-->
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">lc</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#7E</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">lc</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#7E</span><span style="color: #0000FF;">)</span>
Line 4,194: Line 5,378:
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</lang>-->
<!--</syntaxhighlight>-->
{{out}}
{{out}}
<pre>
<pre>
Line 4,202: Line 5,386:


=={{header|Phixmonti}}==
=={{header|Phixmonti}}==
<lang Phixmonti>0 255 repeat var ascCodes
<syntaxhighlight lang="phixmonti">0 255 repeat var ascCodes


"unixdict.txt" "r" fopen var file
"unixdict.txt" "r" fopen var file
Line 4,235: Line 5,419:
endfor
endfor
file fclose
file fclose
endif</lang>
endif</syntaxhighlight>


=={{header|PHP}}==
=={{header|PHP}}==
<lang php><?php
<syntaxhighlight lang="php"><?php
print_r(array_count_values(str_split(file_get_contents($argv[1]))));
print_r(array_count_values(str_split(file_get_contents($argv[1]))));
?></lang>
?></syntaxhighlight>

=={{header|Picat}}==
Sorting on the frequency (decreasing).
<syntaxhighlight lang="picat">go =>
% removing '\n' first
Chars = delete_all(read_file_chars("unixdict.txt"),'\n'),
M = letter_freq(Chars),
println(M.sort_map(values).reverse).

% Get the letter frequency
letter_freq(S) = Map =>
Map = new_map(),
foreach(C in S)
Map.put(C,Map.get(C,0)+1)
end.

% Different sorting function on maps
sort_map(Map,values) = [K=V:_=(K=V) in sort([V=(K=V): K=V in Map])].
sort_map(Map,keys) = sort([KV : KV in Map]).
sort_map(Map) = sort_map(Map,keys).</syntaxhighlight>

{{out}}
<pre>[e = 20144,a = 16421,i = 13980,r = 13436,t = 12836,o = 12738,n = 12097,s = 10210,
l = 10061,c = 8216,u = 6489,m = 5828,d = 5799,p = 5516,h = 5208,g = 4129,b = 4115,
y = 3633,f = 2662,w = 1968,k = 1925,v = 1902,x = 617,z = 433,j = 430,q = 378,
' = 105,. = 6,& = 6,1 = 2,9 = 1,8 = 1,7 = 1,6 = 1,5 = 1,4 = 1,3 = 1,2 = 1,0 = 1]</pre>


=={{header|PicoLisp}}==
=={{header|PicoLisp}}==
<lang PicoLisp>(let Freq NIL
<syntaxhighlight lang="picolisp">(let Freq NIL
(in "file.txt"
(in "file.txt"
(while (char) (accu 'Freq @ 1)) )
(while (char) (accu 'Freq @ 1)) )
(sort Freq) )</lang>
(sort Freq) )</syntaxhighlight>
For a "file.txt":
For a "file.txt":
<pre>abcd
<pre>abcd
Line 4,254: Line 5,464:


=={{header|Pike}}==
=={{header|Pike}}==
<syntaxhighlight lang="pike">
<lang Pike>
string all = Stdio.read_file("README.md");
string all = Stdio.read_file("README.md");
mapping res = ([]);
mapping res = ([]);
Line 4,260: Line 5,470:
res[char]++;
res[char]++;
write("%O\n", res);
write("%O\n", res);
</syntaxhighlight>
</lang>
{{Out}}
{{Out}}
<pre>
<pre>
Line 4,294: Line 5,504:


=={{header|PL/I}}==
=={{header|PL/I}}==
<syntaxhighlight lang="pli">
<lang PL/I>
frequencies: procedure options (main);
frequencies: procedure options (main);
declare tallies(26) fixed binary static initial ((26) 0);
declare tallies(26) fixed binary static initial ((26) 0);
Line 4,318: Line 5,528:
put skip list (substr(alphabet, i, 1), tallies(i));
put skip list (substr(alphabet, i, 1), tallies(i));
end;
end;
end frequencies;</lang>
end frequencies;</syntaxhighlight>
Data:
Data:
<pre>
<pre>
Line 4,356: Line 5,566:


=={{header|PowerShell}}==
=={{header|PowerShell}}==
<syntaxhighlight lang="powershell">
<lang PowerShell>
function frequency ($string) {
function frequency ($string) {
$arr = $string.ToUpper().ToCharArray() |where{$_ -match '[A-KL-Z]'}
$arr = $string.ToUpper().ToCharArray() |where{$_ -match '[A-KL-Z]'}
Line 4,366: Line 5,576:
$file = "$($MyInvocation.MyCommand.Name )" #Put the name of your file here
$file = "$($MyInvocation.MyCommand.Name )" #Put the name of your file here
frequency $(get-content $file -Raw)
frequency $(get-content $file -Raw)
</syntaxhighlight>
</lang>
<b>Output:</b>
<b>Output:</b>
<pre>
<pre>
Line 4,402: Line 5,612:
Only alphabetic codes are computed in uppercase state. <br>
Only alphabetic codes are computed in uppercase state. <br>
Uses '''packlist/2''' defined there : [[Run-length encoding#Prolog]] <br>
Uses '''packlist/2''' defined there : [[Run-length encoding#Prolog]] <br>
<lang Prolog>frequency(File) :-
<syntaxhighlight lang="prolog">frequency(File) :-
read_file_to_codes(File, Code, []),
read_file_to_codes(File, Code, []),


Line 4,455: Line 5,665:
run(Var,[Other|RRest], [1,Var],[Other|RRest]):-
run(Var,[Other|RRest], [1,Var],[Other|RRest]):-
dif(Var,Other).
dif(Var,Other).
</syntaxhighlight>
</lang>
{{out}} for this file
{{out}} for this file
<pre>Number of A : 63
<pre>Number of A : 63
Line 4,474: Line 5,684:
=={{header|PureBasic}}==
=={{header|PureBasic}}==
Alphabetic codes are converted to uppercase before being used and no other codes are used as part of the calculations. <br>
Alphabetic codes are converted to uppercase before being used and no other codes are used as part of the calculations. <br>
<lang PureBasic>Procedure countLetters(Array letterCounts(1), textLine.s)
<syntaxhighlight lang="purebasic">Procedure countLetters(Array letterCounts(1), textLine.s)
;counts only letters A -> Z, uses index 0 of letterCounts() to keep a total of all counts
;counts only letters A -> Z, uses index 0 of letterCounts() to keep a total of all counts
Protected i, lineLength = Len(textLine), letter
Protected i, lineLength = Len(textLine), letter
Line 4,514: Line 5,724:
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
CloseConsole()
CloseConsole()
EndIf</lang>
EndIf</syntaxhighlight>
{{out}}
{{out}}
<pre>File: D:\_T\Text\dictionary.txt
<pre>File: D:\_T\Text\dictionary.txt
Line 4,552: Line 5,762:
====Using collections.Counter====
====Using collections.Counter====
{{works with|Python|2.7+ and 3.1+}}
{{works with|Python|2.7+ and 3.1+}}
<lang python>import collections, sys
<syntaxhighlight lang="python">import collections, sys


def filecharcount(openfile):
def filecharcount(openfile):
Line 4,558: Line 5,768:


f = open(sys.argv[1])
f = open(sys.argv[1])
print(filecharcount(f))</lang>
print(filecharcount(f))</syntaxhighlight>


====As a fold====
====As a fold====
Character counting can be conveniently expressed in terms of fold/reduce. See the example below, which also generates column-wrapped output:
Character counting can be conveniently expressed in terms of fold/reduce. See the example below, which also generates column-wrapped output:
{{Works with|Python|3}}
{{Works with|Python|3}}
<lang python>'''Character counting as a fold'''
<syntaxhighlight lang="python">'''Character counting as a fold'''


from functools import reduce
from functools import reduce
Line 4,728: Line 5,938:
# MAIN ---
# MAIN ---
if __name__ == '__main__':
if __name__ == '__main__':
main()</lang>
main()</syntaxhighlight>
{{Out}}
{{Out}}
<pre>Descending order of frequency:
<pre>Descending order of frequency:
Line 4,750: Line 5,960:
===Procedural===
===Procedural===
====Without using collections.Counter====
====Without using collections.Counter====
<lang python>import string
<syntaxhighlight lang="python">import string
if hasattr(string, 'ascii_lowercase'):
if hasattr(string, 'ascii_lowercase'):
letters = string.ascii_lowercase # Python 2.2 and later
letters = string.ascii_lowercase # Python 2.2 and later
Line 4,773: Line 5,983:
lettercounts = countletters(sourcedata)
lettercounts = countletters(sourcedata)
for i in xrange(len(lettercounts)):
for i in xrange(len(lettercounts)):
print "%s=%d" % (chr(i + ord('a')), lettercounts[i]),</lang>
print "%s=%d" % (chr(i + ord('a')), lettercounts[i]),</syntaxhighlight>


This example defines the function and provides a sample usage. The ''if ... __main__...'' line allows it to be cleanly imported into any other Python code while also allowing it to function as a standalone script. (A very common Python idiom).
This example defines the function and provides a sample usage. The ''if ... __main__...'' line allows it to be cleanly imported into any other Python code while also allowing it to function as a standalone script. (A very common Python idiom).
Line 4,781: Line 5,991:
====Using defaultdict====
====Using defaultdict====
{{works with|Python|2.5+ and 3.x}}
{{works with|Python|2.5+ and 3.x}}
<lang python>...
<syntaxhighlight lang="python">...
from collections import defaultdict
from collections import defaultdict
def countletters(file_handle):
def countletters(file_handle):
Line 4,792: Line 6,002:
c = char.lower()
c = char.lower()
results[c] += 1
results[c] += 1
return results</lang>
return results</syntaxhighlight>


Which eliminates the ungainly fiddling with ordinal values and offsets in function countletters of a previous example above. More importantly it allows the results to be more simply printed using:
Which eliminates the ungainly fiddling with ordinal values and offsets in function countletters of a previous example above. More importantly it allows the results to be more simply printed using:


<lang python>lettercounts = countletters(sourcedata)
<syntaxhighlight lang="python">lettercounts = countletters(sourcedata)
for letter,count in lettercounts.iteritems():
for letter,count in lettercounts.iteritems():
print "%s=%s" % (letter, count),</lang>
print "%s=%s" % (letter, count),</syntaxhighlight>


Again eliminating all fussing with the details of converting letters into list indices.
Again eliminating all fussing with the details of converting letters into list indices.
Line 4,804: Line 6,014:
=={{header|Quackery}}==
=={{header|Quackery}}==


<lang Quackery> [ [] 26 times [ 0 join ] ] is makecountnest ( --> [ )
<syntaxhighlight lang="quackery"> [ [] 26 times [ 0 join ] ] is makecountnest ( --> [ )


[ char A char Z 1+ within ] is ischar ( c --> b )
[ char A char Z 1+ within ] is ischar ( c --> b )
Line 4,828: Line 6,038:
join fail ]
join fail ]
countchars
countchars
echocount ] is fileletters ( $ --> )</lang>
echocount ] is fileletters ( $ --> )</syntaxhighlight>


'''Testing in Quackery shell:'''
'''Testing in Quackery shell:'''
Line 4,876: Line 6,086:
=={{header|Quick Basic/QBASIC/PDS 7.1/VB-DOS}}==
=={{header|Quick Basic/QBASIC/PDS 7.1/VB-DOS}}==
This version counts valid letters from A to Z (including Ñ in Spanish alphabet) or characters in a file. Takes in account accented vowels. It runs in QB, QBASIC, PDS 7.1 and VB_DOS as is.
This version counts valid letters from A to Z (including Ñ in Spanish alphabet) or characters in a file. Takes in account accented vowels. It runs in QB, QBASIC, PDS 7.1 and VB_DOS as is.
<syntaxhighlight lang="vb">
<lang VB>
' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
' Program CountCar '
' Program CountCar '
Line 5,118: Line 6,328:
' ---End of main program cycle
' ---End of main program cycle


</syntaxhighlight>
</lang>


Output:
Output:
Line 5,147: Line 6,357:
=={{header|R}}==
=={{header|R}}==
===Using summary===
===Using summary===
<lang R>letter.frequency <- function(filename)
<syntaxhighlight lang="rsplus">letter.frequency <- function(filename)
{
{
file <- paste(readLines(filename), collapse = '')
file <- paste(readLines(filename), collapse = '')
chars <- strsplit(file, NULL)[[1]]
chars <- strsplit(file, NULL)[[1]]
summary(factor(chars))
summary(factor(chars))
}</lang>
}</syntaxhighlight>


Usage on itself:
Usage on itself:


<lang R>> source('letter.frequency.r')
<syntaxhighlight lang="rsplus">> source('letter.frequency.r')
> letter.frequency('letter.frequency.r')
> letter.frequency('letter.frequency.r')
- , . ' ( ) [ ] { } < = 1 a c d e f h i l L m n N o p q r s t u U y
- , . ' ( ) [ ] { } < = 1 a c d e f h i l L m n N o p q r s t u U y
22 3 2 1 2 6 6 2 2 1 1 3 1 1 9 6 1 14 7 2 7 8 3 4 6 1 3 3 1 8 8 7 3 1 2 </lang>
22 3 2 1 2 6 6 2 2 1 1 3 1 1 9 6 1 14 7 2 7 8 3 4 6 1 3 3 1 8 8 7 3 1 2 </syntaxhighlight>
===Using table===
===Using table===
R's table function is more idiomatic. For variety, we will use read.delim rather than readLines and show how to only count letters. It is worth noting that readLines is prone to counting empty lines. This may be undesirable.
R's table function is more idiomatic. For variety, we will use read.delim rather than readLines and show how to only count letters. It is worth noting that readLines is prone to counting empty lines. This may be undesirable.
<lang R>letterFreq<-function(filename,lettersOnly)
<syntaxhighlight lang="rsplus">letterFreq <- function(filename, lettersOnly)
{
{
txt<-read.delim(filename,header = FALSE,stringsAsFactors = FALSE,allowEscapes = FALSE,quote = "")
txt <- read.delim(filename, header = FALSE, stringsAsFactors = FALSE, allowEscapes = FALSE, quote = "")
count<-table(strsplit(paste0(txt[,],collapse = ""),""))
count <- table(strsplit(paste0(txt[,], collapse = ""), ""))
if(lettersOnly){count[names(count)%in%c(LETTERS,letters)]}
if(lettersOnly) count[names(count) %in% c(LETTERS, letters)] else count
}</syntaxhighlight>
else{count}
}</lang>
{{out}}
{{out}}
For fun, we'll use this page for input. However, HTML rarely parses well and the variety of text here is so large that I suspect inaccurate output.
For fun, we'll use this page for input. However, HTML rarely parses well and the variety of text here is so large that I suspect inaccurate output.
<pre>file<-'https://rosettacode.org/wiki/Letter_frequency'
<pre>> print(letterFreq('https://rosettacode.org/wiki/Letter_frequency', TRUE))
> letterFreq(file,TRUE)


a A b B c C d D e E f F g G h H i I
a A b B c C d D e E f F g G h H i I
Line 5,182: Line 6,390:


=={{header|Racket}}==
=={{header|Racket}}==
<lang racket>
<syntaxhighlight lang="racket">
#lang racket
#lang racket
(require math)
(require math)
Line 5,191: Line 6,399:


(letter-frequencies (open-input-string "abaabdc"))
(letter-frequencies (open-input-string "abaabdc"))
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 5,199: Line 6,407:


Using input from a text file:
Using input from a text file:
<lang racket>
<syntaxhighlight lang="racket">
(letter-frequencies (open-input-file "somefile.txt"))
(letter-frequencies (open-input-file "somefile.txt"))
</syntaxhighlight>
</lang>


=={{header|Raku}}==
=={{header|Raku}}==
(formerly Perl 6)
(formerly Perl 6)

In Raku, whenever you want to count things in a collection, the rule of thumb is to use the Bag structure.
In Raku, whenever you want to count things in a collection, the rule of thumb is to use the Bag structure.

<lang perl6>.&ws.say for slurp.comb.Bag.sort: -*.value;
<div style="background:#ffffee;padding:1em;">
''In response to some of the breathless exposition in the [[Letter_frequency#Frink|Frink]] entry.''

* Has a Unicode-aware function, which intelligently enumerates through what a human would consider to be a single visible character. - Raku doesn't have '''a''' special Unicode aware string processing function, rather '''all''' of Rakus text/string wrangling functions are Unicode aware by default.

* Unicode-aware lowercase function. - See above: lowercase, uppercase, fold-case, title-case, all Unicode aware by default.

* Uses full Unicode tables to determine what is a "letter." - Um... Yeah, Unicode aware by default.

* Works with high Unicode characters, that is above \uFFFF. - OK, now we're just repeating ourselves.

* Normalize Unicode characters with its normalizeUnicode function. - Raku; normalized by default.

* Implements all of (NFC, NFD, NFKC, NFKD). NFC is the default. - Yep.

"How many other languages in this page do all or any of this correctly?" Quite a few I suspect. Some even moreso than Frink.
</div>

<syntaxhighlight lang="raku" line>.&ws.say for slurp.comb.Bag.sort: -*.value;


sub ws ($pair) {
sub ws ($pair) {
Line 5,214: Line 6,442:
?? ($pair.key.uniname => $pair.value)
?? ($pair.key.uniname => $pair.value)
!! $pair
!! $pair
}</lang>
}</syntaxhighlight>
{{Out|Output when fed the same Les Misérables text file as used in the [[Word_frequency#Raku|Word frequency]] task}}
{{Out|Output when fed the same Les Misérables text file as used in the [[Word_frequency#Raku|Word frequency]] task}}
<pre>SPACE => 522095
<pre>SPACE => 522095
Line 5,333: Line 6,561:


=={{header|Raven}}==
=={{header|Raven}}==
<lang Raven>define count_letters use $words
<syntaxhighlight lang="raven">define count_letters use $words
{ } as $wordHash [ ] as $keys [ ] as $vals
{ } as $wordHash [ ] as $keys [ ] as $vals
$words each chr
$words each chr
Line 5,345: Line 6,573:
"test.dat" as $file
"test.dat" as $file
$file read as $all_data
$file read as $all_data
$all_data count_letters</lang>
$all_data count_letters</syntaxhighlight>


=={{header|Refal}}==
<syntaxhighlight lang="refal">$ENTRY Go {
, <Arg 1>: {
= <Prout 'No filename given'>;
e.File, <ReadFile 1 e.File>: e.Text,
<Tally e.Text>: e.Counts
= <ShowLetterCounts (e.Counts) <Letters>>;
};
};

Letters {
= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
};

ShowLetterCounts {
(e.T) = ;
(e.T) s.L e.Ls,
<Upper s.L>: s.UL, <Item (e.T) s.UL>: s.ULN,
<Lower s.L>: s.LL, <Item (e.T) s.LL>: s.LLN,
<+ s.ULN s.LLN>: s.Total
= <Prout s.UL s.LL ': ' <Symb s.Total>>
<ShowLetterCounts (e.T) e.Ls>;
};

ReadFile {
s.Chan e.Filename =
<Open 'r' s.Chan e.Filename>
<ReadFile (s.Chan)>;
(s.Chan), <Get s.Chan>: {
0 = <Close s.Chan>;
e.Line = e.Line '\n' <ReadFile (s.Chan)>;
};
};

Tally {
(e.T) = e.T;
(e.T) s.X e.Xs = <Tally (<Inc (e.T) s.X>) e.Xs>;
e.Xs = <Tally () e.Xs>;
}

Inc {
(e.1 (s.I s.N) e.2) s.I = e.1 (s.I <+ 1 s.N>) e.2;
(e.X) s.I = e.X (s.I 1);
};

Item {
(e.1 (s.I s.N) e.2) s.I = s.N;
(e.X) s.I = 0;
};</syntaxhighlight>
{{out}}
The result of running the program on its own source file:
<pre>Aa: 22
Bb: 2
Cc: 16
Dd: 5
Ee: 75
Ff: 10
Gg: 5
Hh: 11
Ii: 26
Jj: 1
Kk: 1
Ll: 49
Mm: 8
Nn: 33
Oo: 18
Pp: 6
Qq: 1
Rr: 17
Ss: 55
Tt: 44
Uu: 14
Vv: 2
Ww: 5
Xx: 12
Yy: 7
Zz: 1</pre>
=={{header|REXX}}==
=={{header|REXX}}==
===version 1===
===version 1===
Line 5,362: Line 6,667:


All characters are still counted, whether a letter or not, including non-displayable characters.
All characters are still counted, whether a letter or not, including non-displayable characters.
<lang rexx>/*REXX program counts the occurrences of all characters in a file, and note that all */
<syntaxhighlight lang="rexx">/*REXX program counts the occurrences of all characters in a file, and note that all */
/* Latin alphabet letters are uppercased for also counting {Latin} letters (both cases).*/
/* Latin alphabet letters are uppercased for also counting {Latin} letters (both cases).*/
/*════════════════════════════════════~~~~~~~~~~════════════════════════════════════════*/
/*════════════════════════════════════~~~~~~~~~~════════════════════════════════════════*/
Line 5,403: Line 6,708:
say /*not a good place for dithering: ░▒▓█ */
say /*not a good place for dithering: ░▒▓█ */
say pad pad9 '☼ end─of─list ☼' /*show we are at the end of the list. */
say pad pad9 '☼ end─of─list ☼' /*show we are at the end of the list. */
/*§§§§ Talk about a mishmash of 2¢ comments. ▬▬^▬▬ stick a fork in it, we're all done. ☻*/</lang>
/*§§§§ Talk about a mishmash of 2¢ comments. ▬▬^▬▬ stick a fork in it, we're all done. ☻*/</syntaxhighlight>
'''output''' &nbsp; when using the (above) REXX program for the input file:
'''output''' &nbsp; when using the (above) REXX program for the input file:


Line 5,579: Line 6,884:


===Version 2 (for TSO)===
===Version 2 (for TSO)===
<lang rexx>/*REXX program counts the occurences of all characters in a file
<syntaxhighlight lang="rexx">/*REXX program counts the occurences of all characters in a file
* Adapted version 1 for TSO (EXECIO instead of linein)
* Adapted version 1 for TSO (EXECIO instead of linein)
* No translation to uppercase takes place
* No translation to uppercase takes place
Line 5,639: Line 6,944:
end
end
end
end
say 'file -----' dsn "----- has" other 'other characters.'</lang>
say 'file -----' dsn "----- has" other 'other characters.'</syntaxhighlight>
Output:
Output:
<pre>
<pre>
Line 5,668: Line 6,973:


=={{header|Ring}}==
=={{header|Ring}}==
<lang ring>
<syntaxhighlight lang="ring">
textData = read("C:\Ring\ReadMe.txt")
textData = read("C:\Ring\ReadMe.txt")
ln =len(textData)
ln =len(textData)
Line 5,683: Line 6,988:
if charCount[i] > 0 see char(i) + " = " + charCount[i] + " " + (charCount[i]/totCount)*100 + " %" + nl ok
if charCount[i] > 0 see char(i) + " = " + charCount[i] + " " + (charCount[i]/totCount)*100 + " %" + nl ok
next
next
</syntaxhighlight>
</lang>

=={{header|RPL}}==
« → text
« { 26 } 0 CON
1 text SIZE '''FOR''' j
text j DUP SUB NUM
'''IF''' DUP 97 ≥ OVER 122 ≤ AND '''THEN''' 32 - '''END'''
'''IF''' DUP 65 ≥ OVER 90 ≤ AND '''THEN''' 64 - DUP2 GET 1 + PUT '''ELSE''' DROP '''END'''
'''NEXT'''
{ }
1 26 '''FOR''' j
'''IF''' OVER j GET '''THEN''' LASTARG j 64 + CHR →TAG + '''END'''
'''NEXT''' SWAP DROP
» » '<span style="color:blue">AZFREQ</span>' STO

'<span style="color:blue">AZFREQ</span>' DUP RCL →STR SWAP EVAL <span style="color:grey">@ have the program count its own letters</span>
{{out}}
<pre>
1: { :A: 5 :B: 1 :C: 2 :D: 9 :E: 17 :F: 5 :G: 4 :H: 4 :I: 4 :J: 5 :L: 1 :M: 1 :N: 12 :O: 6 :P: 5 :R: 7 :S: 3 :T: 16 :U: 7 :V: 3 :X: 5 :Z: 1 }
</pre>


=={{header|Ruby}}==
=={{header|Ruby}}==
<lang ruby>def letter_frequency(file)
<syntaxhighlight lang="ruby">def letter_frequency(file)
letters = 'a' .. 'z'
letters = 'a' .. 'z'
File.read(file) .
File.read(file) .
Line 5,695: Line 7,020:
end
end


letter_frequency(ARGV[0]).sort_by {|key, val| -val}.each {|pair| p pair}</lang>
letter_frequency(ARGV[0]).sort_by {|key, val| -val}.each {|pair| p pair}</syntaxhighlight>
example output, using the program file as input:
example output, using the program file as input:
<pre>$ ruby letterFrequency.rb letterFrequency.rb
<pre>$ ruby letterFrequency.rb letterFrequency.rb
Line 5,723: Line 7,048:


===Ruby 2.0===
===Ruby 2.0===
<lang ruby>def letter_frequency(file)
<syntaxhighlight lang="ruby">def letter_frequency(file)
freq = Hash.new(0)
freq = Hash.new(0)
file.each_char.lazy.grep(/[[:alpha:]]/).map(&:upcase).each_with_object(freq) do |char, freq_map|
file.each_char.lazy.grep(/[[:alpha:]]/).map(&:upcase).each_with_object(freq) do |char, freq_map|
Line 5,732: Line 7,057:
letter_frequency(ARGF).sort.each do |letter, frequency|
letter_frequency(ARGF).sort.each do |letter, frequency|
puts "#{letter}: #{frequency}"
puts "#{letter}: #{frequency}"
end</lang>
end</syntaxhighlight>


note that this version *should* use less memory, even on a gigantic file. This is done by using lazy enumerables, which ruby 2.0 introduces.
note that this version *should* use less memory, even on a gigantic file. This is done by using lazy enumerables, which ruby 2.0 introduces.
Line 5,784: Line 7,109:
===Ruby 2.7===
===Ruby 2.7===
Ruby 2.7 introduced "tally", which delivers a tally on anything enumerable.
Ruby 2.7 introduced "tally", which delivers a tally on anything enumerable.
<lang ruby>p File.open("/usr/share/dict/words","r").each_char.tally</lang>
<syntaxhighlight lang="ruby">p File.open("/usr/share/dict/words","r").each_char.tally</syntaxhighlight>


=={{header|Run BASIC}}==
=={{header|Run BASIC}}==
<lang Runbasic>open "c:\rbp101\public\textFile.txt" for input as #f
<syntaxhighlight lang="runbasic">open "c:\rbp101\public\textFile.txt" for input as #f
textData$ = input$(#f, lof( #f))
textData$ = input$(#f, lof( #f))
ln =len(textData$)
ln =len(textData$)
Line 5,802: Line 7,127:
for i = 32 to 255
for i = 32 to 255
if charCount(i) > 0 then print "Ascii:";using("###",i);" char:";chr$(i);" Count:";using("#######",charCount(i));" ";using("##.#",(charCount(i) / totCount) * 100);"%"
if charCount(i) > 0 then print "Ascii:";using("###",i);" char:";chr$(i);" Count:";using("#######",charCount(i));" ";using("##.#",(charCount(i) / totCount) * 100);"%"
next i</lang>
next i</syntaxhighlight>


Output uses this program to count itself:
Output uses this program to count itself:
Line 5,855: Line 7,180:
=={{header|Rust}}==
=={{header|Rust}}==
Works with all UTF-8 characters
Works with all UTF-8 characters
<lang rust>use std::collections::btree_map::BTreeMap;
<syntaxhighlight lang="rust">use std::collections::btree_map::BTreeMap;
use std::{env, process};
use std::{env, process};
use std::io::{self, Read, Write};
use std::io::{self, Read, Write};
Line 5,889: Line 7,214:
writeln!(&mut io::stderr(), "{}", msg).expect("Could not write to stderr");
writeln!(&mut io::stderr(), "{}", msg).expect("Could not write to stderr");
process::exit(code)
process::exit(code)
}</lang>
}</syntaxhighlight>


Output when run on source file:
Output when run on source file:
Line 5,962: Line 7,287:
=={{header|S-BASIC}}==
=={{header|S-BASIC}}==
Because S-BASIC lacks an EOF function, some extra care is required to avoid reading beyond the end of file. (CP/M text files are normally terminated with a Ctrl-Z byte, but not all text editors enforce this convention if the file would otherwise end on a sector boundary.)
Because S-BASIC lacks an EOF function, some extra care is required to avoid reading beyond the end of file. (CP/M text files are normally terminated with a Ctrl-Z byte, but not all text editors enforce this convention if the file would otherwise end on a sector boundary.)
<syntaxhighlight lang="s-basic">
<lang S-BASIC>
$constant EOF = 1AH rem normal end-of-file marker
$constant EOF = 1AH rem normal end-of-file marker


Line 6,038: Line 7,363:
9_exit
9_exit
end
end
</syntaxhighlight>
</lang>
{{out}}
{{out}}
With Lincoln's Second Inaugural Address used as input
With Lincoln's Second Inaugural Address used as input
Line 6,073: Line 7,398:
=={{header|Scala}}==
=={{header|Scala}}==


<lang scala>import io.Source.fromFile
<syntaxhighlight lang="scala">import io.Source.fromFile


def letterFrequencies(filename: String) =
def letterFrequencies(filename: String) =
fromFile(filename).mkString groupBy (c => c) mapValues (_.length)</lang>
fromFile(filename).mkString groupBy (c => c) mapValues (_.length)</syntaxhighlight>


=={{header|Scheme}}==
=={{header|Scheme}}==
Line 6,084: Line 7,409:
Note that this prints the scheme representations of characters in no particular order.
Note that this prints the scheme representations of characters in no particular order.


<lang scheme>(use-modules (ice-9 format))
<syntaxhighlight lang="scheme">(use-modules (ice-9 format))


(define (char-freq port table)
(define (char-freq port table)
Line 6,104: Line 7,429:
(format-table (char-freq (open-input-file filename) '())))
(format-table (char-freq (open-input-file filename) '())))


(print-freq "letter-frequency.scm")</lang>
(print-freq "letter-frequency.scm")</syntaxhighlight>


Output when reading own source:
Output when reading own source:
Line 6,147: Line 7,472:
An implementation for CHICKEN scheme:
An implementation for CHICKEN scheme:


<lang scheme>
<syntaxhighlight lang="scheme">
(with-input-from-string "foobar"
(with-input-from-string "foobar"
(lambda ()
(lambda ()
Line 6,156: Line 7,481:
'()
'()
read-char)))
read-char)))
</syntaxhighlight>
</lang>


which shows: ((#\f . 1) (#\o . 2) (#\b . 1) (#\a . 1) (#\r . 1))
which shows: ((#\f . 1) (#\o . 2) (#\b . 1) (#\a . 1) (#\r . 1))


=={{header|Seed7}}==
=={{header|Seed7}}==
<lang seed7>$ include "seed7_05.s7i";
<syntaxhighlight lang="seed7">$ include "seed7_05.s7i";
const type: charHash is hash [char] integer;
const type: charHash is hash [char] integer;
Line 6,182: Line 7,507:
writeln(ch <& " " <& numberOfChars[ch]);
writeln(ch <& " " <& numberOfChars[ch]);
end for;
end for;
end func;</lang>
end func;</syntaxhighlight>


Output when the program uses itself as input:
Output when the program uses itself as input:
Line 6,204: Line 7,529:


=={{header|SenseTalk}}==
=={{header|SenseTalk}}==
<lang sensetalk>
<syntaxhighlight lang="sensetalk">
put file "~/Documents/addresses.csv" into source
put file "~/Documents/addresses.csv" into source


Line 6,216: Line 7,541:
put char 1 of theChar & " —> " & count
put char 1 of theChar & " —> " & count
end repeat
end repeat
</syntaxhighlight>
</lang>
Output:
Output:
<pre>
<pre>
Line 6,295: Line 7,620:


=={{header|Sidef}}==
=={{header|Sidef}}==
<lang ruby>func letter_frequency(File file) {
<syntaxhighlight lang="ruby">func letter_frequency(File file) {
file.read.chars.grep{.match(/[[:alpha:]]/)} \
file.read.chars.grep{.match(/[[:alpha:]]/)} \
.group_by {|letter| letter.downcase} \
.group_by {|letter| letter.downcase} \
Line 6,303: Line 7,628:
var top = letter_frequency(File(__FILE__))
var top = letter_frequency(File(__FILE__))
top.each{|pair| say "#{pair[0]}: #{pair[1]}"}</lang>
top.each{|pair| say "#{pair[0]}: #{pair[1]}"}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 6,332: Line 7,657:
=={{header|SIMPOL}}==
=={{header|SIMPOL}}==
Example: open a text file and compute letter frequency.
Example: open a text file and compute letter frequency.
<lang simpol>constant iBUFSIZE 500
<syntaxhighlight lang="simpol">constant iBUFSIZE 500


function main(string filename)
function main(string filename)
Line 6,374: Line 7,699:
end while
end while
end if
end if
end function s</lang>
end function s</syntaxhighlight>


As this was being created I realized that in [SIMPOL] I wouldn't have done it this way (in fact, I wrote it differently the first time and had to go back and change it to use an array afterward). In [SIMPOL] we would have used the set object. It acts similarly to a single-dimensional array, but can also use various set operations, such as difference, unite, intersect, etc. One of th einteresting things is that each unique value is stored only once, and the number of duplicates is stored with it. The sample then looks a little cleaner:
As this was being created I realized that in [SIMPOL] I wouldn't have done it this way (in fact, I wrote it differently the first time and had to go back and change it to use an array afterward). In [SIMPOL] we would have used the set object. It acts similarly to a single-dimensional array, but can also use various set operations, such as difference, unite, intersect, etc. One of th einteresting things is that each unique value is stored only once, and the number of duplicates is stored with it. The sample then looks a little cleaner:


<lang simpol>constant iBUFSIZE 500
<syntaxhighlight lang="simpol">constant iBUFSIZE 500


function main(string filename)
function main(string filename)
Line 6,414: Line 7,739:
end while
end while
end if
end if
end function s</lang>
end function s</syntaxhighlight>


The final stage simply reads the totals for each character. One caveat, if a character is unrepresented, then it will not show up at all in this second implementation.
The final stage simply reads the totals for each character. One caveat, if a character is unrepresented, then it will not show up at all in this second implementation.
Line 6,421: Line 7,746:
Make it a bag of characters and get the counts:
Make it a bag of characters and get the counts:
{{works with|Smalltalk/X}}
{{works with|Smalltalk/X}}
<lang smalltalk>bagOfChars := 'someFile' asFilename contentsAsString asBag.
<syntaxhighlight lang="smalltalk">bagOfChars := 'someFile' asFilename contentsAsString asBag.
bag sortedCounts
bag sortedCounts
select:[:assoc | assoc value isLetter ]
select:[:assoc | assoc value isLetter ]
thenDo:[:assoc | assoc printCR].</lang>
thenDo:[:assoc | assoc printCR].</syntaxhighlight>
If the file is huge, you may not want to read it in as a big string first, but feed the chars linewise into the bag:
If the file is huge, you may not want to read it in as a big string first, but feed the chars linewise into the bag:
<lang smalltalk>bagOfChars := Bag new.
<syntaxhighlight lang="smalltalk">bagOfChars := Bag new.
'someFile' asFilename readingLinesDo:[:eachLine | bagOfChars addAll:eachLine].
'someFile' asFilename readingLinesDo:[:eachLine | bagOfChars addAll:eachLine].
bag sortedCounts ...</lang>
bag sortedCounts ...</syntaxhighlight>


To show all counts (as opposed to selecting the letter counts only), replace the "select:thenDo:" by a simple "do:", as in:
To show all counts (as opposed to selecting the letter counts only), replace the "select:thenDo:" by a simple "do:", as in:
<lang smalltalk>bag sortedCounts do:[:assoc | assoc printCR].</lang>
<syntaxhighlight lang="smalltalk">bag sortedCounts do:[:assoc | assoc printCR].</syntaxhighlight>
or even shorter:
or even shorter:
<lang smalltalk>bag sortedCounts do:#printCR.</lang>
<syntaxhighlight lang="smalltalk">bag sortedCounts do:#printCR.</syntaxhighlight>
{{out}}
{{out}}
<pre>27->e
<pre>27->e
Line 6,442: Line 7,767:
...</pre>
...</pre>
If you prefer seeing the character first, followed by the count, replace the do-loop's action with:
If you prefer seeing the character first, followed by the count, replace the do-loop's action with:
<lang smalltalk>... do:[:assoc | '%s -> %s\n' printf:{assoc value . assoc key} on:Stdout ].</lang>
<syntaxhighlight lang="smalltalk">... do:[:assoc | '%s -> %s\n' printf:{assoc value . assoc key} on:Stdout ].</syntaxhighlight>
{{out}}
{{out}}
<pre>e -> 27
<pre>e -> 27
Line 6,452: Line 7,777:
=={{header|Swift}}==
=={{header|Swift}}==


<lang swift>import Foundation
<syntaxhighlight lang="swift">import Foundation


let dictPath: String
let dictPath: String
Line 6,470: Line 7,795:
for (char, count) in counts {
for (char, count) in counts {
print("\(char): \(count)")
print("\(char): \(count)")
}</lang>
}</syntaxhighlight>


=={{header|Tcl}}==
=={{header|Tcl}}==
<lang tcl>proc letterHistogram {fileName} {
<syntaxhighlight lang="tcl">proc letterHistogram {fileName} {
# Initialize table (in case of short texts without every letter)
# Initialize table (in case of short texts without every letter)
for {set i 97} {$i<=122} {incr i} {
for {set i 97} {$i<=122} {incr i} {
Line 6,491: Line 7,816:
}
}


letterHistogram the/sample.txt</lang>
letterHistogram the/sample.txt</syntaxhighlight>


=={{header|TUSCRIPT}}==
=={{header|TUSCRIPT}}==
<lang tuscript>
<syntaxhighlight lang="tuscript">
$$ MODE TUSCRIPT
$$ MODE TUSCRIPT
words = REQUEST ("http://www.puzzlers.org/pub/wordlists/unixdict.txt")
words = REQUEST ("http://www.puzzlers.org/pub/wordlists/unixdict.txt")
Line 6,517: Line 7,842:


*{frequency}
*{frequency}
</syntaxhighlight>
</lang>
Output:
Output:
<pre style='height:30ex;overflow:scroll'>
<pre style='height:30ex;overflow:scroll'>
Line 6,565: Line 7,890:
===TXR Extraction Language plus TXR Lisp===
===TXR Extraction Language plus TXR Lisp===


<lang txr>@(do (defvar h (hash :equal-based)))
<syntaxhighlight lang="txr">@(do (defvar h (hash :equal-based)))
@(repeat)
@(repeat)
@(coll :vars ())@\
@(coll :vars ())@\
Line 6,573: Line 7,898:
@(end)
@(end)
@(do (dohash (key value h)
@(do (dohash (key value h)
(format t "~a: ~a\n" key value)))</lang>
(format t "~a: ~a\n" key value)))</syntaxhighlight>


{{out}}
{{out}}
Line 6,588: Line 7,913:
===TXR Lisp===
===TXR Lisp===


<lang txrlisp>(let* ((s (open-file "/usr/share/dict/words" "r"))
<syntaxhighlight lang="txrlisp">(let* ((s (open-file "/usr/share/dict/words" "r"))
(chrs [keep-if* chr-isalpha (gun (get-char s))])
(chrs [keep-if* chr-isalpha (gun (get-char s))])
(h [group-reduce (hash) chr-toupper (op succ @1) chrs 0]))
(h [group-reduce (hash) chr-toupper (op succ @1) chrs 0]))
(dohash (key value h)
(dohash (key value h)
(put-line `@key: @value`)))</lang>
(put-line `@key: @value`)))</syntaxhighlight>


=={{header|Vala}}==
=={{header|Vala}}==
{{libheader|Gee}}
{{libheader|Gee}}
Counts every character except new line character.
Counts every character except new line character.
<lang vala>
<syntaxhighlight lang="vala">
using Gee;
using Gee;


Line 6,618: Line 7,943:
}
}
}
}
</syntaxhighlight>
</lang>


Sample output (run on its own source code) with several lines omitted:
Sample output (run on its own source code) with several lines omitted:
Line 6,635: Line 7,960:
=={{header|VBA}}==
=={{header|VBA}}==


<syntaxhighlight lang="vba">
<lang VBA>
Public Sub LetterFrequency(fname)
Public Sub LetterFrequency(fname)
'count number of letters in text file "fname" (ASCII-coded)
'count number of letters in text file "fname" (ASCII-coded)
Line 6,675: Line 8,000:
Close
Close
End Sub
End Sub
</syntaxhighlight>
</lang>


Output:
Output:
Line 6,710: Line 8,035:


=={{header|VBScript}}==
=={{header|VBScript}}==
<syntaxhighlight lang="vb">
<lang vb>
filepath = "SPECIFY FILE PATH HERE"
filepath = "SPECIFY FILE PATH HERE"


Line 6,735: Line 8,060:
Set objfso = Nothing
Set objfso = Nothing
Set objdict = Nothing
Set objdict = Nothing
</syntaxhighlight>
</lang>


=={{header|Vedit macro language}}==
=={{header|Vedit macro language}}==


<lang vedit>File_Open("c:\txt\a_text_file.txt")
<syntaxhighlight lang="vedit">File_Open("c:\txt\a_text_file.txt")
Update()
Update()


Line 6,746: Line 8,071:
#2 = Search(@103, BEGIN+ALL+NOERR)
#2 = Search(@103, BEGIN+ALL+NOERR)
Message(@103) Num_Type(#2)
Message(@103) Num_Type(#2)
}</lang>
}</syntaxhighlight>


Example output:
Example output:
Line 6,776: Line 8,101:
Y 16
Y 16
Z 2
Z 2
</pre>

=={{header|V (Vlang)}}==

<syntaxhighlight lang="v (vlang)">import os
struct LetterFreq {
rune int
freq int
}

fn main(){
file := os.read_file('unixdict.txt')?
mut freq := map[rune]int{}
for c in file {
freq[c]++
}
mut lf := []LetterFreq{}
for k,v in freq {
lf << LetterFreq{u8(k),v}
}
lf.sort_with_compare(fn(a &LetterFreq, b &LetterFreq)int{
if a.freq > b.freq {
return -1
}
if a.freq < b.freq {
return 1
}
return 0
})
for f in lf {
println('${u8(f.rune).ascii_str()} ${f.rune} $f.freq')
}
}</syntaxhighlight>
{{out}}

<pre> D 25103

A 25103
e 65 20144
a 61 16421
i 69 13980
r 72 13436
t 74 12836
o 6F 12738
n 6E 12097
s 73 10210
l 6C 10061
c 63 8216
u 75 6489
m 6D 5828
d 64 5799
p 70 5516
h 68 5208
g 67 4129
b 62 4115
y 79 3633
f 66 2662
w 77 1968
k 6B 1925
v 76 1902
x 78 617
z 7A 433
j 6A 430
q 71 378
' 27 105
& 26 6
. 2E 6
1 31 2
8 38 1
7 37 1
6 36 1
5 35 1
4 34 1
3 33 1
2 32 1
0 30 1
9 39 1
</pre>
</pre>


=={{header|Whitespace}}==
=={{header|Whitespace}}==


<lang Whitespace>
<syntaxhighlight lang="whitespace">


Line 6,833: Line 8,235:




</syntaxhighlight>
</lang>
<lang asm>push 127
<syntaxhighlight lang="asm">push 127
; Initialize a slot in the heap for each ASCII character.
; Initialize a slot in the heap for each ASCII character.
0:
0:
Line 6,885: Line 8,287:
4:
4:
pop
pop
exit</lang>
exit</syntaxhighlight>


{{out}}
{{out}}
Line 6,897: Line 8,299:
{{libheader|Wren-fmt}}
{{libheader|Wren-fmt}}
As we have a copy to hand, we count the number of letters in the MIT 10000 word list which apparently contains nothing other than lower case letters.
As we have a copy to hand, we count the number of letters in the MIT 10000 word list which apparently contains nothing other than lower case letters.
<lang ecmascript>import "io" for File
<syntaxhighlight lang="wren">import "io" for File
import "/fmt" for Fmt
import "./fmt" for Fmt


var text = File.read("mit10000.txt")
var text = File.read("mit10000.txt")
Line 6,918: Line 8,320:
Fmt.print(" $5d 100.00", totalFreq)
Fmt.print(" $5d 100.00", totalFreq)


Fmt.print("\nTotal characters in text file = $d minus 10000 \\n's = $d", text.count, totalFreq)</lang>
Fmt.print("\nTotal characters in text file = $d minus 10000 \\n's = $d", text.count, totalFreq)</syntaxhighlight>


{{out}}
{{out}}
Line 6,964: Line 8,366:
character ($1A). Usage: count <filename.ext
character ($1A). Usage: count <filename.ext


<lang XPL0>include c:\cxpl\codes; \intrinsic 'code' declarations
<syntaxhighlight lang="xpl0">include c:\cxpl\codes; \intrinsic 'code' declarations
int A(256), C, I;
int A(256), C, I;
[for C:= 0 to 256-1 do A(C):= 0;
[for C:= 0 to 256-1 do A(C):= 0;
Line 6,982: Line 8,384:
if (I&7) = 7 then [CrLf(0); C:= C-8*16+1];
if (I&7) = 7 then [CrLf(0); C:= C-8*16+1];
];
];
]</lang>
]</syntaxhighlight>


Example output of count.xpl counting itself:
Example output of count.xpl counting itself:
Line 6,988: Line 8,390:


=={{header|Yabasic}}==
=={{header|Yabasic}}==
<lang Yabasic>dim ascCodes(255)
<syntaxhighlight lang="yabasic">dim ascCodes(255)


f = open("unixdict.txt", "r")
f = open("unixdict.txt", "r")
Line 7,005: Line 8,407:
next
next
close #f
close #f
end if</lang>
end if</syntaxhighlight>


=={{header|zkl}}==
=={{header|zkl}}==
<lang zkl>fcn ccnt(textInBitBucket){
<syntaxhighlight lang="zkl">fcn ccnt(textInBitBucket){
letters:=["a".."z"].pump(List().write,0); // array of 26 zeros
letters:=["a".."z"].pump(List().write,0); // array of 26 zeros
textInBitBucket.howza(0).pump(Void,'wrap(c){ // pump text as ints
textInBitBucket.howza(0).pump(Void,'wrap(c){ // pump text as ints
Line 7,023: Line 8,425:


ccnt(Data(0,Int,"This is a test"));
ccnt(Data(0,Int,"This is a test"));
ccnt(File("dict.txt").read());</lang>
ccnt(File("dict.txt").read());</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 7,034: Line 8,436:


=={{header|Zoea}}==
=={{header|Zoea}}==
<syntaxhighlight lang="zoea">
<lang Zoea>
program: letter_frequency
program: letter_frequency
input: 'cbcacb' # can be literal value, stdin or file url at runtime
input: 'cbcacb' # can be literal value, stdin or file url at runtime
derive: [[a,1],[b,2],[c,3]]
derive: [[a,1],[b,2],[c,3]]
output: 'a : 1\nb : 2\nc : 3\n'
output: 'a : 1\nb : 2\nc : 3\n'
</syntaxhighlight>
</lang>


=={{header|Zoea Visual}}==
=={{header|Zoea Visual}}==

Latest revision as of 08:24, 30 April 2024

Task
Letter frequency
You are encouraged to solve this task according to the task description, using any language you may know.
Task

Open a text file and count the occurrences of each letter.

Some of these programs count all characters (including punctuation), but some only count letters A to Z.


Other tasks related to string operations:
Metrics
Counting
Remove/replace
Anagrams/Derangements/shuffling
Find/Search/Determine
Formatting
Song lyrics/poems/Mad Libs/phrases
Tokenize
Sequences



11l

Translation of: Python
F countletters(s)
   DefaultDict[Char, Int] results
   L(char) s
      V c = char.lowercase()
      I c C ‘a’..‘z’
         results[c]++
   R results

:start:
L(letter, count) countletters(File(:argv[1]).read())
   print(letter‘=’count)
Output:
d=1
e=1
h=1
l=3
o=2
r=1
w=1

8080 Assembly

This program prints the frequency of each printable ASCII character contained in the file.

bdos:		equ	5	; CP/M syscalls 
putch:		equ	2	; Print a character
puts:		equ	9	; Print a string
fopen:		equ	15	; Open a file
fread:		equ	20	; Read a file
fcb:		equ	5ch	; FCB for file given on command line
dma:		equ	80h	; Default DMA
		org	100h	; CP/M loads the program starting at page 1
		;; Zero out pages two and three (to keep a 16-bit counter
		;; for each possible byte in the file).
		;; We can do this because this program is small enough to
		;; fit in page 1 in its entirety.
		xra	a	; Zero A.
		mov	b,a	; Zero B too (make it loop 256 times)
		lxi	d,200h	; Start of page two
zero:		stax	d	; Zero out a byte (store A, which is zero)
		inx	d	; Next byte
		stax	d	; Zero out another byte
		inx	d	; Next byte
		dcr	b	; Decrement the loop counter.
		jnz	zero	; Continue until B comes back to zero.
		;; Open the file given on the command line. 
		lxi	d,fcb	; CP/M always tries to parse the command line,
		mvi	c,fopen	; and gives us a file "object" in page zero.
		call	bdos	; We can just call fopen on it.
		inr	a	; It sets A=FF on error, so if incrementing A
		jz	error	; rolls back over to 0, that's an error.
		;; Process the file record by record.
		;; In CP/M, each file consists of a number of 128-byte
		;; records. An exact size is not kept.
		;; If a text file is not an exact multiple of 128 bytes
		;; long, the last record will contain a ^Z (26 decimal),
		;; and anything after that byte should be ignored.
read:		lxi	d,fcb	; From the file control block (the "object"),
		mvi	c,fread	; read one record. By default it ends up in
		call	bdos	; the last half of page zero.
		ana	a	; Zero carry flag.
		rar		; Low bit says if end reached
		jc	output	; If so, go print the table
		ana	a	; If any other bits are set, that's a
		jnz	error	; read error.
		;; Count the characters in the current record.
		lxi	d,dma-1	; Set DE to point just before the record
byte:		inr	e	; Go to the next byte.
		jz	read	; If end of record, go get next record.
		ldax	d	; Grab the current byte 
		cpi	26	; If it is EOF, we're done.
		jz	output	; Go print the table 
		mov	l,a	; Otherwise, increment the counter for this
		mvi	h,2	; character: the low byte is kept in page 2.
		inr	m	; 'm' means the value in memory at HL.
		jnz	byte	; If no rollover, we're done; count next byte
		inr	h	; But we're keeping a 16-bit counter, so
		inr	m	; if there is rollover, increment high byte.
		jmp	byte	; The high byte is in page 3 -unorthodox, but
				; it's easy to access here.
		;; We've done the whole file. For each printable
		;; ASCII character (32..126), print the character and
		;; the count. 
output:		mvi	a,32	; Start at 32.
		;; Print a character and its counter
char:		mov	l,a	; Load 16-bit counter into DE. Low byte
		mvi	h,2	; is in page 2 at a;
		mov	e,m
		inr	h	; And the high byte is in page 3.
		mov	d,m
		mov	a,d	; Test if the counter is zero
		ora	e
		mov	a,l	; Put the character back in A
		jz	next	; If zero, don't print anything.
		push	psw	; If not, push the character,
		push	d	; and the counter.
		mvi	c,putch	; Print the current character
		mov	e,a
		call	bdos	
		lxi	d,separator	; Then print ': '
		call 	outs
		;; Then convert the counter to ASCII
		pop	d 	; Retrieve the counter 
		lxi	h,numend	; Get pointer to end of digit string
		push	h	; And put it on the stack
dgtloop:	xchg		; Put counter in HL (16-bit accumulator)
		lxi	b,-10	; Dividend is 10 
		mov	d,b	; Start quotient at -1 (we'll loop once
		mov	e,b	; too many, this corrects for it)
divloop:	inx	d	; Increment the quotient,
		dad	b	; subtract 10 from the dividend,
		jc	divloop	; and keep doing it until it goes negative
		lxi	b,10+'0'	; Add 10 back to get the remainder,
		dad	b		; plus '0' to make it ASCII.
		mov	a,l	
		pop	h	; Retrieve digit pointer
		dcx	h	; Decrement it (to point at current digit)
		mov	m,a	; Store the digit
		push	h	; And store the new pointer
		mov	a,d	; Check if the quotient is now zero
		ora	e
		jnz	dgtloop	; If not, do the next digit.
		pop	d	; Set DE to point at the first digit
		call	outs	; And output it as a string.
		pop	psw	; Restore the character
next:		inr	a	; Increment it
		cpi	127	; Did we just do the last character?
		jnz	char	; If not, go do the next character.
		ret		; If so, we're done.
		;; Print the error message
error:		lxi	d,errmsg
		;; Print string
outs:		mvi	c,puts
		jmp	bdos
		;; Strings
errmsg:		db	'?$'	; "Error message" (if file error)
separator:	db	': $'	; Goes in between character and number
number:		db	'00000'	; Space to keep ASCII representation of 
numend:		db	13,10,'$'	; a 16-bit number, plus newline.

8th

needs map/iter

8 var, numtasks
var tasks

0 args "Give filename as param" thrownull 
f:slurp >s s:len numtasks @ n:/ n:ceil 1 a:close s:/ a:len numtasks ! constant work

m:new constant result

: print-character-count  \ m s -- m 
  swap over m:@  rot   s:size 1 n:= over   -1 s:@ nip 31 n:<  and if
    -1 s:@ nip "<%d>" s:strfmt
  else
      "'%s'" s:strfmt
   then
   "%s: %d\n" s:strfmt . ;

: print-results
  tasks @ a:len ( a:pop t:result nip ( result -rot m:[]! drop ) m:each drop ) swap times drop
  result ( nip array? if ' n:+ 0 a:reduce then ) m:map
  m:keys ' s:cmp a:sort ' print-character-count m:iter drop ;

: task  \ slice --
  "" s:/ ' noop a:group 
  ( nip a:len nip ) m:map ;

: start-tasks
  a:new
  ( work a:pop nip 1 ' task t:task-n a:push ) numtasks @ times
  tasks ! ;

: wait-tasks
  tasks @ t:wait ;

: app:main
  start-tasks
  wait-tasks
  print-results                                         
  bye ;

AArch64 Assembly

Works with: as version Raspberry Pi 3B version Buster 64 bits
or android 64 bits with application Termux
/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program cptletters64.s   */

/************************************/
/* Constantes                       */
/************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc" 
.equ BUFFERSIZE, 300000

/************************************/
/* Initialized data                 */
/************************************/
.data
szMessOpen:           .asciz "File open error.\n"
szMessStat:           .asciz "File information error.\n"
szMessRead:           .asciz "File read error.\n"
szMessClose:          .asciz "File close error.\n"
szMessDecryptText:    .asciz "Decrypted text :\n"
szMessCryptText:      .asciz "Encrypted text :\n"
szMessErrorChar:      .asciz "Character text not Ok!\n"
szFileName:           .asciz "unixdict.txt"
//szFileName:           .asciz "test1.txt"
szMessResult:         .asciz "Result:    = "
szCarriageReturn:     .asciz "\n"
szMessStart:          .asciz "Program 64 bits start.\n"
/************************************/
/* UnInitialized data               */
/************************************/
.bss 
sZoneConv:            .skip 24
tabCptLetters:        .skip 8 * 52         // (A-Z a-z) counter array
sBuffer:              .skip BUFFERSIZE     // file buffer
/************************************/
/*  code section                    */
/************************************/
.text
.global main   
main:                        // entry of program
    ldr x0,qAdrszMessStart
    bl affichageMess
    mov x0,AT_FDCWD
    ldr x1,qAdrszFileName    // file name
    mov x2,#O_RDWR           // flags
    mov x3,#0                // mode 
    mov x8,#OPEN             // file open
    svc 0 
    cmp x0,#0                // error ?
    ble 99f
    mov x9,x0                // FD save

    mov x0,x9
    ldr x1,qAdrsBuffer
    ldr x2,#iBufferSize
    mov x8,#READ             // call system read file
    svc 0 
    cmp x0,#0                // error read ?
    blt 97f
    mov x6,x0                // file size
    mov x0,x9
    mov x8,#CLOSE            // call system close file
    svc 0 
    cmp x0,#0                // error close ?
    blt 96f    
    ldr x0,qAdrsBuffer
    mov x1,x6
    bl cptLetters
    
    b 100f
96:
    ldr x0,qAdrszMessClose
    bl affichageMess     
    mov x0,#-1               // error
    b 100f
97:
    ldr x0,qAdrszMessRead
    bl affichageMess 
    mov x0,#-1               // error
    b 100f
99:
    ldr x0,qAdrszMessOpen
    bl  affichageMess    
    mov x0,#-1               // error

100:                         // standard end of the program
    mov x0, #0               // return code
    mov x8, #EXIT            // request to exit program
    svc 0                    // perform the system call

qAdrsZoneConv:            .quad  sZoneConv
qAdrszMessResult:         .quad  szMessResult
qAdrszCarriageReturn:     .quad  szCarriageReturn
qAdrszMessStart:          .quad  szMessStart
qAdrszFileName:           .quad  szFileName
qAdrszMessOpen:           .quad  szMessOpen
qAdrszMessRead:           .quad  szMessRead
qAdrszMessStat:           .quad  szMessStat
qAdrszMessClose:          .quad  szMessClose
qAdrsBuffer:              .quad  sBuffer
iBufferSize:              .quad  BUFFERSIZE
/***************************************************/
/*   letters frequency                   */
/***************************************************/
/* r0 contains a file buffer */
/* r1 contains string length */
cptLetters:
    stp x1,lr,[sp,-16]!
    stp x2,x3,[sp,-16]! 
    stp x4,x5,[sp,-16]! 
    stp x6,x7,[sp,-16]! 
    ldr x4,qAdrtabCptLetters   // counter array
    mov x3,#0              // index string
1:
    ldrb w2,[x0,x3]        // load byte of string
    cmp x2,#'A'            // select alpha characters lower or upper
    blt 5f
    cmp x2,#'Z'
    bgt 2f
    sub x5,x2,#65          // convert ascii upper in index array (0-25)
    b 3f
2:
    cmp x2,#'z'
    bgt 5f
    cmp x2,#'a'
    blt 5f
    sub x5,x2,#97 - 26     // convert ascii lower in index array (26,52]
3:
    ldr x7,[x4,x5,lsl #3]  // load counter of load character
    add x7,x7,#1           // increment counter 
    str x7,[x4,x5,lsl #3]  // and store
5:
    add x3,x3,#1           // increment text index
    cmp x3,x1              // end ? 
    blt 1b                 // and loop
    
    ldr x7,qAdrszMessResult
    mov x2,65              // for upper ascci character
    mov x3,#0
6:                         // result display
    ldr x1,[x4,x3,lsl #3]  // load counter
    cmp x1,#0              // if zero not display
    beq 7f
    cmp x3,#25             // upper ?
    add x2,x3,65           // for upper ascci character
    add x8,x3,#97 - 26     // lower
    csel x6,x2,x8,le       // compute ascii character
    strb w6,[x7,#9]        // store in message
    mov x0,x1              // convert count in decimal
    ldr x1,qAdrsZoneConv
    bl conversion10
    ldr x0,qAdrszMessResult // and display
    bl affichageMess
    ldr x0,qAdrsZoneConv
    bl affichageMess
    ldr x0,qAdrszCarriageReturn
    bl affichageMess
7:    
    add x3,x3,#1
    cmp x3,#52
    blt 6b
    
 
 100:
    ldp x6,x7,[sp],16
    ldp x4,x5,[sp],16
    ldp x2,x3,[sp],16
    ldp x1,lr,[sp],16                 // TODO: retaur à completer 
    ret 
qAdrtabCptLetters:      .quad  tabCptLetters
/***************************************************/
/*      ROUTINES INCLUDE                           */
/***************************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeARM64.inc"
Output:
Program 64 bits start.
Result:  a = 16421
Result:  b = 4115
Result:  c = 8216
Result:  d = 5799
Result:  e = 20144
Result:  f = 2662
Result:  g = 4129
Result:  h = 5208
Result:  i = 13980
Result:  j = 430
Result:  k = 1925
Result:  l = 10061
Result:  m = 5828
Result:  n = 12097
Result:  o = 12738
Result:  p = 5516
Result:  q = 378
Result:  r = 13436
Result:  s = 10210
Result:  t = 12836
Result:  u = 6489
Result:  v = 1902
Result:  w = 1968
Result:  x = 617
Result:  y = 3633
Result:  z = 433

ACL2

(defun increment-alist (tbl key)
   (cond ((endp tbl) (list (cons key 1)))
         ((eql (car (first tbl)) key)
          (cons (cons key (1+ (cdr (first tbl))))
                (rest tbl)))
         (t (cons (first tbl)
                  (increment-alist (rest tbl) key)))))

(defun freq-table (xs)
   (if (endp xs)
       nil
       (increment-alist (freq-table (rest xs))
                        (first xs))))

(defun letter-freq (str)
   (freq-table (coerce str 'list)))

Action!

INCLUDE "D2:PRINTF.ACT" ;from the Action! Tool Kit

CARD ARRAY histogram(256)

PROC Clear()
  INT i

  FOR i=0 TO 255
  DO histogram(i)=0 OD
RETURN

PROC ProcessLine(CHAR ARRAY line)
  INT i

  FOR i=1 TO line(0)
  DO
    histogram(line(i))==+1
  OD
RETURN

PROC ProcessFile(CHAR ARRAY fname)
  CHAR ARRAY line(255)
  BYTE dev=[1]

  Close(dev)
  Open(dev,fname,4)
  WHILE Eof(dev)=0
  DO
    InputSD(dev,line)
    ProcessLine(line)
  OD
  Close(dev)
RETURN

PROC PrintResult()
  INT i
  CHAR ARRAY s(10)

  FOR i=0 TO 255
  DO
    IF histogram(i) THEN
      StrC(histogram(i),s)
      PrintF(" %C:%-5S",i,s)
    FI
  OD
RETURN

PROC Main()
  CHAR ARRAY fname="H6:LETTE_KJ.ACT"
  BYTE LMARGIN=$52,old

  old=LMARGIN
  LMARGIN=0 ;remove left margin on the screen

  Put(125) PutE() ;clear the screen
  PrintF("Reading ""%S""...%E%E",fname)
  ProcessFile(fname)
  PrintResult()

  LMARGIN=old ;restore left margin on the screen
RETURN
Output:

Screenshot from Atari 8-bit computer

Reading "H6:LETTE_KJ.ACT"...

 :150   !:1     ":12    $:1     %:5
(:27    ):27    +:1     ,:8     -:1
.:5     0:7     1:5     2:7     4:1
5:10    6:2     ::3     ;:4     =:13
A:25    B:2     C:19    D:12    E:16
F:10    G:4     H:8     I:13    J:1
K:2     L:9     M:5     N:15    O:20
P:16    R:44    S:4     T:20    U:6
W:1     Y:8     [:1     ]:1     _:1
a:16    c:9     d:10    e:49    f:9
g:8     h:9     i:36    l:20    m:14
n:29    o:23    p:2     r:25    s:24
t:24    u:5     v:7

Ada

with Ada.Text_IO;

procedure Letter_Frequency is
   Counters: array (Character) of Natural := (others => 0); -- initialize all Counters to 0
   C:        Character;
   File:     Ada.Text_IO.File_Type;

begin
   Ada.Text_IO.Open(File, Mode => Ada.Text_IO.In_File, Name => "letter_frequency.adb");
   while not Ada.Text_IO.End_Of_File(File) loop
      Ada.Text_IO.Get(File, C);
      Counters(C) := Counters(C) + 1;
   end loop;

   for I in Counters'Range loop
      if Counters(I) > 0 then
            Ada.Text_IO.Put_Line("'" & I & "':" & Integer'Image(Counters(I)));
      end if;
   end loop;
end Letter_Frequency;
Output:

(counting the characters of its own source code)

>./letter_frequency
' ': 122
'"': 6
'&': 3

... [a lot of lines omitted]

'x': 7
'y': 5
'z': 1

Aikido

import ctype

var letters = new int [26]

var s = openin (args[0])
while (!s.eof()) {
    var ch = s.getchar()
    if (s.eof()) {
        break
    }
    if (ctype.isalpha (ch)) {
        var n = cast<int>(ctype.tolower(ch) - 'a')
        ++letters[n]
    }
}

foreach i letters.size() {
    println (cast<char>('a' + i) + " " + letters[i])
}

Aime

Letters proper:

file f;
index x;
integer c;

f.affix("unixdict.txt");

while ((c = f.pick) ^ -1) {
    x[c] += 1;
}

c = 'A';
while (c <= 'Z') {
    o_form("%c: /w5/\n", c, x[c] += x[c + 'a' - 'A'] += 0);
    c += 1;
}

All chars:

file f;
index x;
integer c, n;

f.affix("unixdict.txt");

while ((c = f.pick) ^ -1) {
    x[c] += 1;
}

for (c, n in x) {
    o_form("%c: /w5/\n", c, n);
}

ALGOL 68

BEGIN
   [0:max abs char]INT histogram;
   FOR i FROM 0 TO max abs char DO histogram[i] := 0 OD;
   FILE input file;
   STRING input file name = "Letter_frequency.a68";
   IF open (input file, input file name, stand in channel) /= 0 THEN
      put (stand error, ("Cannot open ", input file name, newline));
      stop
   ELSE
      on file end (input file, (REF FILE f) BOOL: (close (f); GOTO finished))
   FI;
   DO
      STRING s;
      get (input file, (s, newline));
      FOR i TO UPB s DO
	 CHAR c = s[i];
	 IF "A" <= c AND c <= "Z" OR "a" <= c AND c <= "z" THEN
	    histogram[ABS c] PLUSAB 1
	 FI
     OD
   OD;
   close (input file);
finished:
   FOR i FROM ABS "A" TO ABS "Z" DO printf (($a3xg(0)l$, REPR i, histogram[i])) OD;
   FOR i FROM ABS "a" TO ABS "z" DO printf (($a3xg(0)l$, REPR i, histogram[i])) OD
END
Output:

Counting letters in its own source code

A   11
B   9
C   2
D   13
E   11
F   14
G   4
H   3
I   10
J   0
[[ Omitted for K – Z and a – p ]]
q   1
r   15
s   19
t   24
u   10
v   0
w   3
x   4
y   1
z   2

APL

      freq{(⍪∪),+/()∘.}

      freq 0 1 2 3 2 3 4 3 4 4 4
0 1
1 1
2 2
3 3
4 4              

      freq 'balloon'
b 1
a 1
l 2
o 2
n 1

The above solution doesn't do the "open a text file" part of the task. File I/O is implementation-dependent, but here's how to do it in Dyalog:

Works with: Dyalog APL
      text  ⎕nget 'filename'

... after which the above freq function can be applied to text.

AppleScript

Procedural

This is probably best handled with vanilla AppleScript and ASObjC each each doing what it does best. The test text used here is the one specified for the Word frequency task.

use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"
use scripting additions

on letterFrequencyinFile(theFile)
    -- Read the file as an NSString, letting the system guess the encoding.
    set fileText to current application's class "NSString"'s stringWithContentsOfFile:(POSIX path of theFile) ¬
        usedEncoding:(missing value) |error|:(missing value)
    -- Get the NSString's non-letter delimited runs, lower-cased, as an AppleScript list of texts.
    -- The switch to vanilla objects is for speed and the ability to extract 'characters'.
    set nonLetterSet to current application's class "NSCharacterSet"'s letterCharacterSet()'s invertedSet()
    script o
        property letterRuns : (fileText's lowercaseString()'s componentsSeparatedByCharactersInSet:(nonLetterSet)) as list
    end script
    
    -- Extract the characters from the runs and add them to an NSCountedSet to have the occurrences of each value counted.
    -- No more than 50,000 characters are extracted in one go to avoid slowing or freezing the script.
    set countedSet to current application's class "NSCountedSet"'s new()
    repeat with i from 1 to (count o's letterRuns)
        set thisRun to item i of o's letterRuns
        set runLength to (count thisRun)
        repeat with i from 1 to runLength by 50000
            set j to i + 49999
            if (j > runLength) then set j to runLength
            tell countedSet to addObjectsFromArray:(characters i thru j of thisRun)
        end repeat
    end repeat
    
    -- Work through the counted set's contents and build a list of records showing how many of what it received.
    set output to {}
    repeat with thisLetter in countedSet's allObjects()
        set thisCount to (countedSet's countForObject:(thisLetter))
        set end of output to {letter:thisLetter, |count|:thisCount}
    end repeat
    
    -- Derive an array of dictionaries from the list and sort it on the letters.
    set output to current application's class "NSMutableArray"'s arrayWithArray:(output)
    set byLetter to current application's class "NSSortDescriptor"'s sortDescriptorWithKey:("letter") ¬
        ascending:(true) selector:("localizedStandardCompare:")
    tell output to sortUsingDescriptors:({byLetter})
    
    -- Convert back to a list of records and return the result.
    return output as list
end letterFrequencyinFile

-- Test with the text file for the "Word frequency" task.
set theFile to ((path to desktop as text) & "135-0.txt") as alias
return letterFrequencyinFile(theFile)
Output:
{{letter:"a", |count|:207133}, {letter:"à", |count|:63}, {letter:"â", |count|:56}, {letter:"æ", |count|:116}, {letter:"b", |count|:37506}, {letter:"c", |count|:67354}, {letter:"ç", |count|:50}, {letter:"d", |count|:108747}, {letter:"e", |count|:330738}, {letter:"é", |count|:1474}, {letter:"è", |count|:299}, {letter:"ê", |count|:74}, {letter:"ë", |count|:5}, {letter:"f", |count|:56206}, {letter:"g", |count|:48598}, {letter:"h", |count|:176839}, {letter:"i", |count|:175288}, {letter:"î", |count|:39}, {letter:"ï", |count|:18}, {letter:"j", |count|:5840}, {letter:"k", |count|:14433}, {letter:"l", |count|:99543}, {letter:"m", |count|:62219}, {letter:"n", |count|:169954}, {letter:"ñ", |count|:2}, {letter:"o", |count|:184388}, {letter:"ô", |count|:34}, {letter:"œ", |count|:38}, {letter:"p", |count|:43387}, {letter:"q", |count|:2533}, {letter:"r", |count|:148671}, {letter:"s", |count|:162047}, {letter:"t", |count|:235526}, {letter:"u", |count|:68270}, {letter:"ù", |count|:18}, {letter:"û", |count|:9}, {letter:"ü", |count|:39}, {letter:"v", |count|:26268}, {letter:"w", |count|:56513}, {letter:"x", |count|:4027}, {letter:"y", |count|:39183}, {letter:"z", |count|:1906}}

Functional

Minimal new code

If we just want to get something up and running (and tabulating output) with a minimum of new code – enough to read the frequencies of shortish texts – we can quickly click together a composition of generic functions.

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions


------------- CHARACTER COUNTS FROM FILE PATH -------------

-- charCounts :: FilePath -> Either String [(Char, Int)]
on charCounts(fp)
    script go
        on |λ|(s)
            |Right|(sortBy(flip(comparing(my snd)), ¬
                map(fanArrow(my head, my |length|), ¬
                    groupBy(my eq, sort(characters of s)))))
        end |λ|
    end script
    
    bindLR(readFileLR(fp), go)
end charCounts


-------------------------- TEST ---------------------------
on run
    set intColumns to 4
    
    either(identity, frequencyTabulation(intColumns), ¬
        charCounts("~/Code/charCount/readme.txt"))
    
end run


------------------------- DISPLAY -------------------------

-- frequencyTabulation :: Int -> [(Char, Int)] -> String
on frequencyTabulation(intCols)
    script
        on |λ|(xs)
            set w to length of (snd(item 1 of xs) as string)
            script go
                on |λ|(x)
                    justifyRight(5, " ", showChar(fst(x))) & ¬
                        " -> " & justifyRight(w, " ", snd(x) as string)
                end |λ|
            end script
            showColumns(intCols, map(go, xs))
        end |λ|
    end script
end frequencyTabulation


-------------------- GENERIC FUNCTIONS --------------------

-- Left :: a -> Either a b
on |Left|(x)
    {type:"Either", |Left|:x, |Right|:missing value}
end |Left|


-- Right :: b -> Either a b
on |Right|(x)
    {type:"Either", |Left|:missing value, |Right|:x}
end |Right|


-- Tuple (,) :: a -> b -> (a, b)
on Tuple(a, b)
    -- Constructor for a pair of values, possibly of two different types.
    {type:"Tuple", |1|:a, |2|:b, length:2}
end Tuple


-- Absolute value.
-- abs :: Num -> Num
on abs(x)
    if 0 > x then
        -x
    else
        x
    end if
end abs


-- bindLR (>>=) :: Either a -> (a -> Either b) -> Either b
on bindLR(m, mf)
    if missing value is not |Left| of m then
        m
    else
        mReturn(mf)'s |λ|(|Right| of m)
    end if
end bindLR


-- chunksOf :: Int -> [a] -> [[a]]
on chunksOf(n, xs)
    set lng to length of xs
    script go
        on |λ|(a, i)
            set x to (i + n) - 1
            if x  lng then
                a & {items i thru -1 of xs}
            else
                a & {items i thru x of xs}
            end if
        end |λ|
    end script
    foldl(go, {}, enumFromThenTo(1, 1 + n, lng))
end chunksOf


-- comparing :: (a -> b) -> (a -> a -> Ordering)
on comparing(f)
    script
        on |λ|(a, b)
            tell mReturn(f)
                set fa to |λ|(a)
                set fb to |λ|(b)
                if fa < fb then
                    -1
                else if fa > fb then
                    1
                else
                    0
                end if
            end tell
        end |λ|
    end script
end comparing


-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
    set lng to length of xs
    set acc to {}
    tell mReturn(f)
        repeat with i from 1 to lng
            set acc to acc & (|λ|(item i of xs, i, xs))
        end repeat
    end tell
    return acc
end concatMap


-- either :: (a -> c) -> (b -> c) -> Either a b -> c
on either(lf, rf, e)
    if missing value is |Left| of e then
        tell mReturn(rf) to |λ|(|Right| of e)
    else
        tell mReturn(lf) to |λ|(|Left| of e)
    end if
end either


-- enumFromThenTo :: Int -> Int -> Int -> [Int]
on enumFromThenTo(x1, x2, y)
    set xs to {}
    set gap to x2 - x1
    set d to max(1, abs(gap)) * (signum(gap))
    repeat with i from x1 to y by d
        set end of xs to i
    end repeat
    return xs
end enumFromThenTo


-- eq (==) :: Eq a => a -> a -> Bool
on eq(a, b)
    a = b
end eq


-- Compose a function from a simple value to a tuple of
-- the separate outputs of two different functions
-- fanArrow (&&&) :: (a -> b) -> (a -> c) -> (a -> (b, c))
on fanArrow(f, g)
    script
        on |λ|(x)
            Tuple(mReturn(f)'s |λ|(x), mReturn(g)'s |λ|(x))
        end |λ|
    end script
end fanArrow


-- flip :: (a -> b -> c) -> b -> a -> c
on flip(f)
    script
        property g : mReturn(f)
        on |λ|(x, y)
            g's |λ|(y, x)
        end |λ|
    end script
end flip


-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from 1 to lng
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldl


-- fst :: (a, b) -> a
on fst(tpl)
    if class of tpl is record then
        |1| of tpl
    else
        item 1 of tpl
    end if
end fst


-- Typical usage: groupBy(on(eq, f), xs)
-- groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
on groupBy(f, xs)
    set mf to mReturn(f)
    
    script enGroup
        on |λ|(a, x)
            if length of (active of a) > 0 then
                set h to item 1 of active of a
            else
                set h to missing value
            end if
            
            if h is not missing value and mf's |λ|(h, x) then
                {active:(active of a) & {x}, sofar:sofar of a}
            else
                {active:{x}, sofar:(sofar of a) & {active of a}}
            end if
        end |λ|
    end script
    
    if length of xs > 0 then
        set dct to foldl(enGroup, {active:{item 1 of xs}, sofar:{}}, rest of xs)
        if length of (active of dct) > 0 then
            sofar of dct & {active of dct}
        else
            sofar of dct
        end if
    else
        {}
    end if
end groupBy


-- head :: [a] -> a
on head(xs)
    if xs = {} then
        missing value
    else
        item 1 of xs
    end if
end head


-- identity :: a -> a
on identity(x)
    -- The argument unchanged.
    x
end identity


-- justifyRight :: Int -> Char -> String -> String
on justifyRight(n, cFiller, strText)
    if n > length of strText then
        text -n thru -1 of ((replicate(n, cFiller) as text) & strText)
    else
        strText
    end if
end justifyRight


-- length :: [a] -> Int
on |length|(xs)
    set c to class of xs
    if list is c or string is c then
        length of xs
    else
        (2 ^ 29 - 1) -- (maxInt - simple proxy for non-finite)
    end if
end |length|


-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    -- The list obtained by applying f
    -- to each element of xs.
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map


-- max :: Ord a => a -> a -> a
on max(x, y)
    if x > y then
        x
    else
        y
    end if
end max

-- maximum :: Ord a => [a] -> a
on maximum(xs)
    script
        on |λ|(a, b)
            if a is missing value or b > a then
                b
            else
                a
            end if
        end |λ|
    end script
    
    foldl(result, missing value, xs)
end maximum


-- partition :: (a -> Bool) -> [a] -> ([a], [a])
on partition(f, xs)
    tell mReturn(f)
        set ys to {}
        set zs to {}
        repeat with x in xs
            set v to contents of x
            if |λ|(v) then
                set end of ys to v
            else
                set end of zs to v
            end if
        end repeat
    end tell
    Tuple(ys, zs)
end partition


-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    -- 2nd class handler function lifted into 1st class script wrapper. 
    if script is class of f then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn


-- readFileLR :: FilePath -> Either String IO String
on readFileLR(strPath)
    set ca to current application
    set e to reference
    set {s, e} to (ca's NSString's ¬
        stringWithContentsOfFile:((ca's NSString's ¬
            stringWithString:strPath)'s ¬
            stringByStandardizingPath) ¬
            encoding:(ca's NSUTF8StringEncoding) |error|:(e))
    if s is missing value then
        |Left|((localizedDescription of e) as string)
    else
        |Right|(s as string)
    end if
end readFileLR


-- Egyptian multiplication - progressively doubling a list, appending
-- stages of doubling to an accumulator where needed for binary 
-- assembly of a target length
-- replicate :: Int -> a -> [a]
on replicate(n, a)
    set out to {}
    if 1 > n then return out
    set dbl to {a}
    
    repeat while (1 < n)
        if 0 < (n mod 2) then set out to out & dbl
        set n to (n div 2)
        set dbl to (dbl & dbl)
    end repeat
    return out & dbl
end replicate


-- showChar :: Char -> String
on showChar(c)
    if space is c then
        "SPACE"
    else if tab is c then
        "TAB"
    else if linefeed is c then
        "LF"
    else
        c
    end if
end showChar


-- showColumns :: Int -> [String] -> String
on showColumns(n, xs)
    set w to maximum(map(my |length|, xs))
    set m to (length of xs) div n
    unlines(map(my unwords, ¬
        transpose(chunksOf(m, xs))))
end showColumns


-- signum :: Num -> Num
on signum(x)
    if x < 0 then
        -1
    else if x = 0 then
        0
    else
        1
    end if
end signum

-- snd :: (a, b) -> b
on snd(tpl)
    if class of tpl is record then
        |2| of tpl
    else
        item 2 of tpl
    end if
end snd


-- sort :: Ord a => [a] -> [a]
on sort(xs)
    ((current application's NSArray's arrayWithArray:xs)'s ¬
        sortedArrayUsingSelector:"compare:") as list
end sort


-- Enough for small scale sorts.
-- Use instead sortOn (Ord b => (a -> b) -> [a] -> [a])
-- which is equivalent to the more flexible sortBy(comparing(f), xs)
-- and uses a much faster ObjC NSArray sort method
-- sortBy :: (a -> a -> Ordering) -> [a] -> [a]
on sortBy(f, xs)
    if length of xs > 1 then
        set h to item 1 of xs
        set f to mReturn(f)
        script
            on |λ|(x)
                f's |λ|(x, h)  0
            end |λ|
        end script
        set lessMore to partition(result, rest of xs)
        sortBy(f, |1| of lessMore) & {h} & ¬
            sortBy(f, |2| of lessMore)
    else
        xs
    end if
end sortBy


-- transpose :: [[String]] -> [[String]]
on transpose(rows)
    script cols
        on |λ|(_, iCol)
            script cell
                on |λ|(row)
                    if iCol > length of row then
                        ""
                    else
                        item iCol of row
                    end if
                end |λ|
            end script
            concatMap(cell, rows)
        end |λ|
    end script
    map(cols, item 1 of rows)
end transpose


-- unlines :: [String] -> String
on unlines(xs)
    -- A single string formed by the intercalation
    -- of a list of strings with the newline character.
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, linefeed}
    set str to xs as text
    set my text item delimiters to dlm
    str
end unlines


-- unwords :: [String] -> String
on unwords(xs)
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, space}
    set s to xs as text
    set my text item delimiters to dlm
    return s
end unwords
Output:
SPACE -> 1330     p ->  138     " ->   28     k ->    5
    e ->  598     | ->  132     L ->   20     U ->    5
  TAB ->  584     g ->  129     F ->   20     < ->    4
    t ->  562     x ->  121     E ->   20     W ->    3
   LF ->  509     > ->  107     I ->   18     G ->    3
    n ->  462     : ->  102     O ->   17     / ->    3
    s ->  423     , ->   98     B ->   17     V ->    2
    - ->  384     y ->   70     A ->   17     H ->    2
    i ->  372     b ->   70     & ->   17     D ->    2
    o ->  365     R ->   42     ' ->   15     4 ->    2
    r ->  316     λ ->   39     ¬ ->   13     + ->    2
    a ->  311     w ->   39     N ->   13     ≥ ->    1
    l ->  241     v ->   35     2 ->   13     ≤ ->    1
    f ->  240     ] ->   35     = ->   12     ~ ->    1
    d ->  198     [ ->   35     q ->   11     _ ->    1
    ) ->  181     C ->   35     0 ->   10     ^ ->    1
    ( ->  181     T ->   33     . ->    9     Y ->    1
    m ->  154     S ->   32     P ->    8     9 ->    1
    h ->  152     1 ->   31     M ->    8     8 ->    1
    c ->  149     } ->   30     j ->    6     5 ->    1
    u ->  141     { ->   30     z ->    5     * ->    1


Minimal run-time

For longer texts, calculating only the frequencies of (case-insensitive and accent-insensitive) (a-z) alphabetics (and re-using here the Project Gutenburg Misérables text from the Word Frequency task), we can do something a little faster with a list of simple regular expressions, again composing a solution from existing generic functions.

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions


------ CASE AND ACCENT-INSENSITIVE FREQUENCIES OF A-Z ----

-- romanLetterFrequencies :: FilePath -> Maybe [(Char, Int)]
on romanLetterFrequencies(fp)
    if doesFileExist(fp) then
        set patterns to enumFromToChar("a", "z")
        
        set counts to ap(map(my matchCount, patterns), ¬
            {readFile(fp)'s ¬
                decomposedStringWithCanonicalMapping's ¬
                lowercaseString})
        
        sortBy(flip(comparing(my snd)))'s ¬
            |λ|(zip(patterns, counts))
    else
        missing value
    end if
end romanLetterFrequencies


--------------------------- TEST -------------------------
on run
    set fpText to scriptFolder() & "miserables.txt"
    
    set azFrequencies to romanLetterFrequencies(fpText)
    
    if missing value is not azFrequencies then
        script arrow
            on |λ|(kv)
                set {k, v} to kv
                unwords({k, "->", v})
            end |λ|
        end script
        unlines(map(arrow, azFrequencies))
    else
        display dialog "Text file not found in this script's folder:" & ¬
            linefeed & tab & fpText
    end if
end run


------------------------- GENERIC ------------------------

-- Tuple (,) :: a -> b -> (a, b)
on Tuple(a, b)
    -- Constructor for a pair of values, possibly of two different types.
    {a, b}
end Tuple


-- ap (<*>) :: [(a -> b)] -> [a] -> [b]
on ap(fs, xs)
    -- e.g. [(*2),(/2), sqrt] <*> [1,2,3]
    -- -->  ap([dbl, hlf, root], [1, 2, 3])
    -- -->  [2,4,6,0.5,1,1.5,1,1.4142135623730951,1.7320508075688772]
    -- Each member of a list of functions applied to
    -- each of a list of arguments, deriving a list of new values
    set lst to {}
    repeat with f in fs
        tell mReturn(contents of f)
            repeat with x in xs
                set end of lst to |λ|(contents of x)
            end repeat
        end tell
    end repeat
    return lst
end ap


-- comparing :: (a -> b) -> (a -> a -> Ordering)
on comparing(f)
    script
        on |λ|(a, b)
            tell mReturn(f)
                set fa to |λ|(a)
                set fb to |λ|(b)
                if fa < fb then
                    -1
                else if fa > fb then
                    1
                else
                    0
                end if
            end tell
        end |λ|
    end script
end comparing


-- doesFileExist :: FilePath -> IO Bool
on doesFileExist(strPath)
    set ca to current application
    set oPath to (ca's NSString's stringWithString:strPath)'s ¬
        stringByStandardizingPath
    set {bln, int} to (ca's NSFileManager's defaultManager's ¬
        fileExistsAtPath:oPath isDirectory:(reference))
    bln and (int  1)
end doesFileExist


-- enumFromToChar :: Char -> Char -> [Char]
on enumFromToChar(m, n)
    set {intM, intN} to {id of m, id of n}
    if intM  intN then
        set xs to {}
        repeat with i from intM to intN
            set end of xs to character id i
        end repeat
        return xs
    else
        {}
    end if
end enumFromToChar


-- flip :: (a -> b -> c) -> b -> a -> c
on flip(f)
    script
        property g : mReturn(f)
        on |λ|(x, y)
            g's |λ|(y, x)
        end |λ|
    end script
end flip


-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    -- The list obtained by applying f
    -- to each element of xs.
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map


-- matchCount :: String -> NSString -> Int
on matchCount(regexString)
    -- A count of the matches for a regular expression
    -- in a given NSString
    script
        on |λ|(s)
            set ca to current application
            ((ca's NSRegularExpression's ¬
                regularExpressionWithPattern:regexString ¬
                    options:(ca's NSRegularExpressionAnchorsMatchLines) ¬
                    |error|:(missing value))'s ¬
                numberOfMatchesInString:s ¬
                    options:0 ¬
                    range:{location:0, |length|:s's |length|()}) as integer
        end |λ|
    end script
end matchCount


-- min :: Ord a => a -> a -> a
on min(x, y)
    if y < x then
        y
    else
        x
    end if
end min


-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    -- 2nd class handler function lifted into 1st class script wrapper. 
    if script is class of f then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn


-- partition :: (a -> Bool) -> [a] -> ([a], [a])
on partition(f, xs)
    tell mReturn(f)
        set ys to {}
        set zs to {}
        repeat with x in xs
            set v to contents of x
            if |λ|(v) then
                set end of ys to v
            else
                set end of zs to v
            end if
        end repeat
    end tell
    {ys, zs}
end partition


-- readFile :: FilePath -> IO NSString
on readFile(strPath)
    set ca to current application
    set e to reference
    set {s, e} to (ca's NSString's ¬
        stringWithContentsOfFile:((ca's NSString's ¬
            stringWithString:strPath)'s ¬
            stringByStandardizingPath) ¬
            encoding:(ca's NSUTF8StringEncoding) |error|:(e))
    if missing value is e then
        s
    else
        (localizedDescription of e) as string
    end if
end readFile


-- scriptFolder :: () -> IO FilePath
on scriptFolder()
    -- The path of the folder containing this script
    tell application "Finder" to ¬
        POSIX path of ((container of (path to me)) as alias)
end scriptFolder


-- snd :: (a, b) -> b
on snd(tpl)
    item 2 of tpl
end snd


-- sortBy :: (a -> a -> Ordering) -> [a] -> [a]
on sortBy(f)
    -- Enough for small scale sorts.
    -- The NSArray sort method in the Foundation library
    -- gives better permormance for longer lists.
    script go
        on |λ|(xs)
            if length of xs > 1 then
                set h to item 1 of xs
                set f to mReturn(f)
                script
                    on |λ|(x)
                        f's |λ|(x, h)  0
                    end |λ|
                end script
                set lessMore to partition(result, rest of xs)
                |λ|(item 1 of lessMore) & {h} & ¬
                    |λ|(item 2 of lessMore)
            else
                xs
            end if
        end |λ|
    end script
end sortBy


-- unlines :: [String] -> String
on unlines(xs)
    -- A single string formed by the intercalation
    -- of a list of strings with the newline character.
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, linefeed}
    set s to xs as text
    set my text item delimiters to dlm
    s
end unlines


-- unwords :: [String] -> String
on unwords(xs)
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, space}
    set s to xs as text
    set my text item delimiters to dlm
    return s
end unwords


-- zip :: [a] -> [b] -> [(a, b)]
on zip(xs, ys)
    zipWith(Tuple, xs, ys)
end zip


-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
on zipWith(f, xs, ys)
    set lng to min(length of xs, length of ys)
    set lst to {}
    if 1 > lng then
        return {}
    else
        tell mReturn(f)
            repeat with i from 1 to lng
                set end of lst to |λ|(item i of xs, item i of ys)
            end repeat
            return lst
        end tell
    end if
end zipWith
Output:
e -> 332590
t -> 235526
a -> 207252
o -> 184422
h -> 176839
i -> 175345
n -> 169956
s -> 162047
r -> 148671
d -> 108747
l -> 99543
u -> 68336
c -> 67404
m -> 62219
w -> 56513
f -> 56206
g -> 48598
p -> 43387
y -> 39183
b -> 37506
v -> 26268
k -> 14433
j -> 5840
x -> 4027
q -> 2533
z -> 1906

Applesoft BASIC

 100  LET F$ = "TEXT FILE"
 110  LET D$ =  CHR$ (4)
 120  DIM C(255)
 130  PRINT D$"OPEN "F$
 140  FOR Q = 0 TO 1 STEP 0
 150      PRINT D$"READ "F$
 160      ONERR  GOTO 240
 170      GET C$
 180      POKE 216,0
 190      LET C =  ASC (C$)
 200      LET C(C) = C(C) + 1
 210      PRINT 
 220  NEXT 
 230  STOP 
 240  POKE 216,0
 250  LET E =  PEEK (222)
 260  PRINT D$"CLOSE "F$
 270  IF E <  > 5 THEN  RESUME 
 280  FOR I = 0 TO 255
 290      IF C(I) THEN  GOSUB 320
 300  NEXT I
 310  END 
 320  IF I < 32 THEN  PRINT "^" CHR$ (64 + I);
 330  IF I >  = 32 AND I < 128 THEN  PRINT  CHR$ (I);
 340  IF I > 127 THEN  PRINT "CHR$("I")";
 350  PRINT "="C(I)"  ";
 360  RETURN

ARM Assembly

Works with: as version Raspberry Pi
or android 32 bits with application Termux
/* ARM assembly Raspberry PI  */
/*  program cptletters.s   */

/************************************/
/* Constantes                       */
/************************************/
/* for this file see task include a file in language ARM assembly*/
.include "../constantes.inc"
.equ READ,   3
.equ WRITE,  4
.equ OPEN,   5
.equ CLOSE,  6
.equ O_RDWR,  0x0002         @ open for reading and writing
.equ BUFFERSIZE, 300000
/************************************/
/* Initialized data                 */
/************************************/
.data
szMessOpen:           .asciz "File open error.\n"
szMessStat:           .asciz "File information error.\n"
szMessRead:           .asciz "File read error.\n"
szMessClose:          .asciz "File close error.\n"
szMessDecryptText:    .asciz "Decrypted text :\n"
szMessCryptText:      .asciz "Encrypted text :\n"
szMessErrorChar:      .asciz "Character text not Ok!\n"
szFileName:           .asciz "unixdict.txt"
//szFileName:           .asciz "test1.txt"
szMessResult:         .asciz "Result:    = "
szCarriageReturn:     .asciz "\n"
szMessStart:          .asciz "Program 32 bits start.\n"
/************************************/
/* UnInitialized data               */
/************************************/
.bss 
sZoneConv:            .skip 24
tabCptLetters:        .skip 4 * 52         @ (A-Z a-z) counter array
sBuffer:              .skip BUFFERSIZE     @ file buffer
/************************************/
/*  code section                    */
/************************************/
.text
.global main   
main:                        @ entry of program
    ldr r0,iAdrszMessStart
    bl affichageMess
    ldr r0,iAdrszFileName    @ file name
    mov r1,#O_RDWR           @ flags
    mov r2,#0                @ mode 
    mov r7,#OPEN             @ file open
    svc 0 
    cmp r0,#0                @ error ?
    ble 99f
    mov r8,r0                @ FD save

    mov r0,r8
    ldr  r1,iAdrsBuffer
    ldr r2,#iBufferSize
    mov r7,#READ             @ call system read file
    svc 0 
    cmp r0,#0                @ error read ?
    blt 97f
    mov r6,r0                @ file size
    mov r0,r8
    mov r7,#CLOSE            @ call system close file
    svc 0 
    cmp r0,#0                @ error close ?
    blt 96f    
    ldr r0,iAdrsBuffer
    mov r1,r6
    bl cptLetters
    
    b 100f
96:
    ldr r0,iAdrszMessClose
    bl affichageMess     
    mov r0,#-1               @ error
    b 100f
97:
    ldr r0,iAdrszMessRead
    bl affichageMess 
    mov r0,#-1               @ error
    b 100f
99:
    ldr r0,iAdrszMessOpen
    bl  affichageMess    
    mov r0,#-1               @ error

100:                         @ standard end of the program
    mov r0, #0               @ return code
    mov r7, #EXIT            @ request to exit program
    svc 0                    @ perform the system call

iAdrsZoneConv:            .int sZoneConv
iAdrszMessResult:         .int szMessResult
iAdrszCarriageReturn:     .int szCarriageReturn
iAdrszMessStart:          .int szMessStart
iAdrszFileName:           .int szFileName
iAdrszMessOpen:           .int szMessOpen
iAdrszMessRead:           .int szMessRead
iAdrszMessStat:           .int szMessStat
iAdrszMessClose:          .int szMessClose
iAdrsBuffer:              .int sBuffer
iBufferSize:              .int BUFFERSIZE
/***************************************************/
/*   letters frequency                   */
/***************************************************/
/* r0 contains a file buffer */
/* r1 contains string length */
cptLetters:
    push {r1-r7,lr}        @ save registers
    ldr r4,iAdrtabCptLetters   @ counter array
    mov r3,#0              @ index string
1:
    ldrb r2,[r0,r3]        @ load byte of string
    cmp r2,#'A'            @ select alpha characters lower or upper
    blt 5f
    cmp r2,#'Z'
    bgt 2f
    sub r5,r2,#65          @ convert ascii upper in index array (0-25)
    b 3f
2:
    cmp r2,#'z'
    bgt 5f
    cmp r2,#'a'
    blt 5f
    sub r5,r2,#97 - 26     @ convert ascii lower in index array (26,52]
3:
    ldr r7,[r4,r5,lsl #2]  @ load counter of load character
    add r7,r7,#1           @ increment counter 
    str r7,[r4,r5,lsl #2]  @ and store
5:
    add r3,r3,#1           @ increment text index
    cmp r3,r1              @ end ? 
    blt 1b                 @ and loop
    
    ldr r7,iAdrszMessResult
    mov r3,#0
6:                         @ result display
    ldr r1,[r4,r3,lsl #2]  @ load counter
    cmp r1,#0              @ if zero not display
    beq 7f
    cmp r3,#25             @ upper ?
    addle r6,r3,#65        @ yes compute ascci character
    addgt r6,r3,#97 - 26   @ lower
    strb r6,[r7,#9]        @ store in message
    mov r0,r1              @ convert count in decimal
    ldr r1,iAdrsZoneConv
    bl conversion10
    ldr r0,iAdrszMessResult @ and display
    bl affichageMess
    ldr r0,iAdrsZoneConv
    bl affichageMess
    ldr r0,iAdrszCarriageReturn
    bl affichageMess
7:    
    add r3,r3,#1
    cmp r3,#52
    blt 6b
    
 
 100:
    pop {r1-r7,pc}  
iAdrtabCptLetters:      .int tabCptLetters
/***************************************************/
/*      ROUTINES INCLUDE                           */
/***************************************************/
/* for this file see task include a file in language ARM assembly*/
.include "../affichage.inc"
Output:

with the file unixdict.txt

Program 32 bits start.
Result:  a = 16421
Result:  b = 4115
Result:  c = 8216
Result:  d = 5799
Result:  e = 20144
Result:  f = 2662
Result:  g = 4129
Result:  h = 5208
Result:  i = 13980
Result:  j = 430
Result:  k = 1925
Result:  l = 10061
Result:  m = 5828
Result:  n = 12097
Result:  o = 12738
Result:  p = 5516
Result:  q = 378
Result:  r = 13436
Result:  s = 10210
Result:  t = 12836
Result:  u = 6489
Result:  v = 1902
Result:  w = 1968
Result:  x = 617
Result:  y = 3633
Result:  z = 433

Arturo

source: {
The Red Death had long devastated the country. 
No pestilence had ever been so fatal, or so hideous. 
Blood was its Avator and its seal—the redness and the horror of blood. 
There were sharp pains, and sudden dizziness, 
and then profuse bleeding at the pores, with dissolution. 
The scarlet stains upon the body and especially upon the face of the victim, 
were the pest ban which shut him out from the aid and from the sympathy of his fellow-men. 
And the whole seizure, progress and termination of the disease, 
were the incidents of half an hour.
}

valid: split "abcdefghijklmnopqrstuvwxyz"
frequencies: #[]

loop split lower source 'ch [
    if in? ch valid [
        if not? key? frequencies ch -> 
            set frequencies ch 0

        set frequencies ch (get frequencies ch)+1
    ]
]

inspect.muted frequencies
Output:
[ :dictionary
	t  :	39 :integer
	h  :	33 :integer
	e  :	60 :integer
	r  :	24 :integer
	d  :	27 :integer
	a  :	33 :integer
	l  :	15 :integer
	o  :	34 :integer
	n  :	30 :integer
	g  :	3 :integer
	v  :	4 :integer
	s  :	34 :integer
	c  :	8 :integer
	u  :	11 :integer
	y  :	5 :integer
	p  :	11 :integer
	i  :	25 :integer
	b  :	6 :integer
	f  :	12 :integer
	w  :	8 :integer
	z  :	3 :integer
	m  :	7 :integer
]

AutoHotkey


This is the past version of this edit but made into a function, and now it only shows the letters that are in it, but not the ones with 0 letters

LetterFreq(Var) {
	Loop, 26
	{
		StrReplace(Var, Chr(96+A_Index), , Count)
		if Count
			out .= Chr(96+A_Index) ": " Count "`n"
	}
	return out
}

var := "The dog jumped over the lazy fox"
var2 := "foo bar"
Msgbox, % LetterFreq(var)
Msgbox, % LetterFreq(var2)
Output:
a: 1
d: 2
e: 4
f: 1
g: 1
h: 2
j: 1
l: 1
m: 1
o: 3
p: 1
r: 1
t: 2
u: 1
v: 1
x: 1
y: 1
z: 1
---------------------------
---------------------------
a: 1
b: 1
f: 1
o: 2
r: 1

AutoIt

This function prints the Letter frequency of a given textfile. You can choose to use case sensitive search and if special chars should be searched too.

Func _Letter_frequency($Path, $fcase = True, $fspecial_chars = True)
	Local $hFile, $sRead, $iupto, $iStart, $iCount
	If Not $fcase Then $fcase = False
	If Not $fspecial_chars Then
		$iStart = 64
		If Not $fcase Then
			$iupto = 26
		Else
			$iupto = 58
		EndIf
	Else
		$iStart = 31
		$iupto = 224
	EndIf
	$hFile = FileOpen($Path, 0)
	$sRead = FileRead($hFile)
	FileClose($hFile)
	For $i = 1 To $iupto
		If Not $fspecial_chars Then
			If $iStart + $i > 90 And $iStart + $i < 97 Then ContinueLoop
		EndIf
		$sRead = StringReplace($sRead, Chr($iStart + $i), "", 0, $fcase)
		$iCount = @extended
		If $iCount > 0 Then ConsoleWrite(Chr($iStart + $i) & " : " & $iCount & @CRLF)
	Next
EndFunc   ;==>_Letter_frequency
Output:
A : 32
B : 2
C : 15
E : 31
F : 10
[several lines omitted]
u : 14
v : 1
w : 1
x : 14

AWK

# usage: awk -f letters.awk HolyBible.txt

BEGIN { FS="" }
      { for(i=1;i<=NF;i++) m[$i]++}
END   { for(i in m) printf("%9d %-14s\n", m[i],i) }

BaCon

txt$ = LOAD$("bible.txt")

FOR x = 97 TO 122
    PRINT CHR$(x-32), " ", CHR$(x), " : ", COUNT(txt$, x-32), " - ", COUNT(txt$, x)
NEXT
Output:
A a : 17915 - 257815
B b : 4714 - 44161
C c : 1698 - 53373
D d : 8782 - 149313
E e : 2710 - 409525
F f : 2386 - 81157
G g : 6206 - 49096
H h : 3208 - 279471
I i : 13302 - 180660
J j : 6374 - 2515
K k : 547 - 21745
L l : 9222 - 120716
M m : 3056 - 76884
N n : 1891 - 223166
O o : 8896 - 234290
P p : 1877 - 41377
Q q : 6 - 958
R r : 7568 - 162761
S s : 4906 - 185124
T t : 7763 - 309983
U u : 333 - 83140
V v : 107 - 30258
W w : 2408 - 63079
X x : 2 - 1476
Y y : 569 - 58007
Z z : 904 - 2068

BBC BASIC

      DIM cnt%(255)
      
      file% = OPENIN("C:\unixdict.txt")
      IF file%=0 ERROR 100, "Could not open file"
      
      REPEAT
        A$ = GET$#file%
        L% = LEN(A$)
        IF L% THEN
          FOR I% = 1 TO L%
            cnt%(ASCMID$(A$,I%)) += 1
          NEXT
        ENDIF
      UNTIL EOF#file%
      CLOSE #file%
      
      FOR c% = &41 TO &5A
        PRINT CHR$(c%)CHR$(c%+32) ": " cnt%(c%)+cnt%(c%+32)
      NEXT
Output:
Aa:      16421
Bb:       4115
Cc:       8216
Dd:       5799
Ee:      20144
Ff:       2662
Gg:       4129
Hh:       5208
Ii:      13980
Jj:        430
Kk:       1925
Ll:      10061
Mm:       5828
Nn:      12097
Oo:      12738
Pp:       5516
Qq:        378
Rr:      13436
Ss:      10210
Tt:      12836
Uu:       6489
Vv:       1902
Ww:       1968
Xx:        617
Yy:       3633
Zz:        433

BCPL

get "libhdr"

let start() be
$(  let count = vec 255
    let file = findinput("unixdict.txt")
    
    for i = 0 to 255 do i!count := 0
    
    selectinput(file)
    $(  let ch = rdch()
        if ch = endstreamch then break
        ch!count := ch!count + 1
    $) repeat
    
    for i = 'A' to 'Z' do
    $(  let n = i!count + (i|32)!count
        unless n = 0 do
            writef("%C%C: %I5*N", i, i|32, n)
    $)
    
    endread()
$)
Output:
Aa: 16421
Bb:  4115
Cc:  8216
Dd:  5799
Ee: 20144
Ff:  2662
Gg:  4129
Hh:  5208
Ii: 13980
Jj:   430
Kk:  1925
Ll: 10061
Mm:  5828
Nn: 12097
Oo: 12738
Pp:  5516
Qq:   378
Rr: 13436
Ss: 10210
Tt: 12836
Uu:  6489
Vv:  1902
Ww:  1968
Xx:   617
Yy:  3633
Zz:   433

BQN

"sample.txt" can be substituted with any filename.

Freq⍷≍/

Freq "balloon"
# For a file:
Freq •FLines "sample.txt"
┌─                     
╵ 'b' 'a' 'l' 'o' 'n'  
  1   1   2   2   1    
                      ┘

Bracmat

(lc=
  counts c
.     fil$(!arg,r)                        {open file for reading}
    & 0:?counts
    &   whl
      ' ( fil$:?c                         {read a byte}
        &     ( !c:(~<A:~>Z|~<a:~>z)
              | 0
              )
            + !counts
          : ?counts                       {simply add any found letter to the sum}
        )
    & fil$(,SET,-1)                       {close the file by seeking to impossible file position.}
  | !counts                               {return the sum}
);

lc$"valid.bra"                            {example: count letters in Bracmat's validation suite.}
107*A
+ 33*B
+ 37*C
+ 39*D
+ 74*E
+ 50*F
+ 27*G
+ 28*H
+ 20*I
+ 55*J
+ 32*K
+ 112*L
+ 36*M
+ 32*N
+ 621*O
+ 43*P
+ 25*R
+ 67*S
+ 62*T
+ 64*U
+ 5*V
+ 26*W
+ 353*X
+ 248*Y
+ 70*Z
+ 2173*a
+ 840*b
+ 738*c
+ 639*d
+ 1345*e
+ 472*f
+ 372*g
+ 568*h
+ 91*j
+ 142*k
+ 529*l
+ 409*m
+ 941*n
+ 840*o
+ 336*p
+ 65*q
+ 993*r
+ 1018*s
+ 2097*t
+ 978*u
+ 122*v
+ 156*w
+ 909*x
+ 685*y
+ 211*z
+ 1035*i

C

/* declare array */
int frequency[26];
int ch;
FILE* txt_file = fopen ("a_text_file.txt", "rt");

/* init the freq table: */
for (ch = 0; ch < 26; ch++)
    frequency[ch] = 0;

while (1) {
    ch = fgetc(txt_file);
    if (ch == EOF) break; /* end of file or read error.  EOF is typically -1 */

    /* assuming ASCII; "letters" means "a to z" */
    if ('a' <= ch && ch <= 'z')      /* lower case */
        frequency[ch-'a']++;
    else if ('A' <= ch && ch <= 'Z') /* upper case */
        frequency[ch-'A']++;
}

C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

class Program
{
    static SortedDictionary<TItem, int> GetFrequencies<TItem>(IEnumerable<TItem> items)
    {
        var dictionary = new SortedDictionary<TItem, int>();
        foreach (var item in items)
        {
            if (dictionary.ContainsKey(item))
            {
                dictionary[item]++;
            }
            else
            {
                dictionary[item] = 1;
            }
        }
        return dictionary;
    }

    static void Main(string[] arguments)
    {
        var file = arguments.FirstOrDefault();
        if (File.Exists(file))
        {
            var text = File.ReadAllText(file);
            foreach (var entry in GetFrequencies(text))
            {
                Console.WriteLine("{0}: {1}", entry.Key, entry.Value);
            }
        }
    }
}
Output:
 : 1
!: 1
,: 1
H: 1
d: 1
e: 1
l: 3
o: 2
r: 1
w: 1

Declarative approach:

var freq =  from c in str
            where char.IsLetter(c)
            orderby c
            group c by c into g
            select g.Key + ":" + g.Count();

foreach(var g in freq)
    Console.WriteLine(g);
C:2
I:1
K:1
L:2
W:1
a:4
...
y:2

C++

#include <fstream>
#include <iostream>

int main()
{
	std::ifstream input("filename.txt", std::ios_base::binary);
	if (!input)
	{
		std::cerr << "error: can't open file\n";
		return -1;
	}

	size_t count[256];
	std::fill_n(count, 256, 0);

	for (char c; input.get(c); ++count[uint8_t(c)]) // process input file
		; // empty loop body

	for (size_t i = 0; i < 256; ++i)
	{
		if (count[i] && isgraph(i)) // non-zero counts of printable characters
		{
			std::cout << char(i) << " = " << count[i] << '\n';
		}
	}
}
Output:

when file contains "Hello, world!" (without quotes)

! = 1
, = 1
H = 1
d = 1
e = 1
l = 3
o = 2
r = 1
w = 1

Clojure

(println (sort-by second > 
			(frequencies (map #(java.lang.Character/toUpperCase %)
					  (filter #(java.lang.Character/isLetter %) (slurp "text.txt"))))))

Common Lisp

(defun letter-freq (file)
  (with-open-file (stream file)
    (let ((str (make-string (file-length stream)))
	  (arr (make-array 256 :element-type 'integer :initial-element 0)))
      (read-sequence str stream)
      (loop for c across str do (incf (aref arr (char-code c))))
      (loop for c from 32 to 126 for i from 1 do
	    (format t "~c: ~d~a"
		    (code-char c) (aref arr c)
		    (if (zerop (rem i 8)) #\newline #\tab))))))

(letter-freq "test.lisp")

COBOL

       IDENTIFICATION DIVISION.
       PROGRAM-ID. Letter-Frequency.
       AUTHOR.  Bill Gunshannon.
       INSTALLATION.  Home.
       DATE-WRITTEN.  12 December 2021.
      ************************************************************
      ** Program Abstract:
      **   A rather simplistic program to do the kind of thing
      **   that COBOL does really well.                
      ************************************************************
       
       ENVIRONMENT DIVISION.
       
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
            SELECT Text-File ASSIGN TO "File.txt"
                 ORGANIZATION IS LINE SEQUENTIAL.
       
       DATA DIVISION.
       
       FILE SECTION.
       
       FD  Text-File
           DATA RECORD IS Record-Name.
       01  Record-Name           PIC X(80).
       
       
       WORKING-STORAGE SECTION.
       
       01 Eof                   PIC X     VALUE 'F'.

       01  Letter-cnt.
           05  A-cnt            PIC 9(5)    VALUE 0.
           05  B-cnt            PIC 9(5)    VALUE 0.
           05  C-cnt            PIC 9(5)    VALUE 0.
           05  D-cnt            PIC 9(5)    VALUE 0.
           05  E-cnt            PIC 9(5)    VALUE 0.
           05  F-cnt            PIC 9(5)    VALUE 0.
           05  G-cnt            PIC 9(5)    VALUE 0.
           05  H-cnt            PIC 9(5)    VALUE 0.
           05  I-cnt            PIC 9(5)    VALUE 0.
           05  J-cnt            PIC 9(5)    VALUE 0.
           05  K-cnt            PIC 9(5)    VALUE 0.
           05  L-cnt            PIC 9(5)    VALUE 0.
           05  M-cnt            PIC 9(5)    VALUE 0.
           05  N-cnt            PIC 9(5)    VALUE 0.
           05  O-cnt            PIC 9(5)    VALUE 0.
           05  P-cnt            PIC 9(5)    VALUE 0.
           05  Q-cnt            PIC 9(5)    VALUE 0.
           05  R-cnt            PIC 9(5)    VALUE 0.
           05  S-cnt            PIC 9(5)    VALUE 0.
           05  T-cnt            PIC 9(5)    VALUE 0.
           05  U-cnt            PIC 9(5)    VALUE 0.
           05  V-cnt            PIC 9(5)    VALUE 0.
           05  W-cnt            PIC 9(5)    VALUE 0.
           05  X-cnt            PIC 9(5)    VALUE 0.
           05  Y-cnt            PIC 9(5)    VALUE 0.
           05  Z-cnt            PIC 9(5)    VALUE 0.
       
       01  Letter-disp.
           05  A-cnt            PIC ZZZZ9.
           05  B-cnt            PIC ZZZZ9.
           05  C-cnt            PIC ZZZZ9.
           05  D-cnt            PIC ZZZZ9.
           05  E-cnt            PIC ZZZZ9.
           05  F-cnt            PIC ZZZZ9.
           05  G-cnt            PIC ZZZZ9.
           05  H-cnt            PIC ZZZZ9.
           05  I-cnt            PIC ZZZZ9.
           05  J-cnt            PIC ZZZZ9.
           05  K-cnt            PIC ZZZZ9.
           05  L-cnt            PIC ZZZZ9.
           05  M-cnt            PIC ZZZZ9.
           05  N-cnt            PIC ZZZZ9.
           05  O-cnt            PIC ZZZZ9.
           05  P-cnt            PIC ZZZZ9.
           05  Q-cnt            PIC ZZZZ9.
           05  R-cnt            PIC ZZZZ9.
           05  S-cnt            PIC ZZZZ9.
           05  T-cnt            PIC ZZZZ9.
           05  U-cnt            PIC ZZZZ9.
           05  V-cnt            PIC ZZZZ9.
           05  W-cnt            PIC ZZZZ9.
           05  X-cnt            PIC ZZZZ9.
           05  Y-cnt            PIC ZZZZ9.
           05  Z-cnt            PIC ZZZZ9.
       
       PROCEDURE DIVISION.
       
       Main-Program.
           OPEN INPUT  Text-File
           PERFORM UNTIL Eof = 'T'
              READ  Text-File
                    AT END MOVE 'T' to Eof
              END-READ
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING A-cnt OF Letter-cnt  FOR ALL 'A'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING B-cnt OF Letter-cnt  FOR ALL 'B'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING C-cnt OF Letter-cnt  FOR ALL 'C'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING D-cnt OF Letter-cnt  FOR ALL 'D'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING E-cnt OF Letter-cnt  FOR ALL 'E'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING F-cnt OF Letter-cnt  FOR ALL 'F'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING G-cnt OF Letter-cnt  FOR ALL 'G'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING H-cnt OF Letter-cnt  FOR ALL 'H'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING I-cnt OF Letter-cnt  FOR ALL 'I'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING J-cnt OF Letter-cnt  FOR ALL 'J'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING K-cnt OF Letter-cnt  FOR ALL 'K'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING L-cnt OF Letter-cnt  FOR ALL 'L'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING M-cnt OF Letter-cnt  FOR ALL 'M'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING N-cnt OF Letter-cnt  FOR ALL 'N'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING O-cnt OF Letter-cnt  FOR ALL 'O'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING P-cnt OF Letter-cnt  FOR ALL 'P'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING Q-cnt OF Letter-cnt  FOR ALL 'Q'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING R-cnt OF Letter-cnt  FOR ALL 'R'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING S-cnt OF Letter-cnt  FOR ALL 'S'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING T-cnt OF Letter-cnt  FOR ALL 'T'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING U-cnt OF Letter-cnt  FOR ALL 'U'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING V-cnt OF Letter-cnt  FOR ALL 'V'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING W-cnt OF Letter-cnt  FOR ALL 'W'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING X-cnt OF Letter-cnt  FOR ALL 'X'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING Y-cnt OF Letter-cnt  FOR ALL 'Y'
           INSPECT FUNCTION UPPER-CASE(Record-Name)
                   TALLYING Z-cnt OF Letter-cnt  FOR ALL 'Z'
           END-PERFORM.
           CLOSE Text-File.
           MOVE CORRESPONDING Letter-cnt To Letter-disp.
           DISPLAY 'Letter Frequency Distribution'.
           DISPLAY '-----------------------------'.
           DISPLAY 'A : ' A-cnt OF Letter-disp '          '
                   'N : ' N-cnt OF Letter-disp.
           DISPLAY 'B : ' B-cnt OF Letter-disp '          '
                   'O : ' O-cnt OF Letter-disp.
           DISPLAY 'C : ' C-cnt OF Letter-disp '          '
                   'P : ' P-cnt OF Letter-disp.
           DISPLAY 'D : ' D-cnt OF Letter-disp '          '
                   'Q : ' Q-cnt OF Letter-disp.
           DISPLAY 'E : ' E-cnt OF Letter-disp '          '
                   'R : ' R-cnt OF Letter-disp.
           DISPLAY 'F : ' F-cnt OF Letter-disp '          '
                   'S : ' S-cnt OF Letter-disp.
           DISPLAY 'G : ' G-cnt OF Letter-disp '          '
                   'T : ' T-cnt OF Letter-disp.
           DISPLAY 'H : ' H-cnt OF Letter-disp '          '
                   'U : ' U-cnt OF Letter-disp.
           DISPLAY 'I : ' I-cnt OF Letter-disp '          '
                   'V : ' V-cnt OF Letter-disp.
           DISPLAY 'J : ' J-cnt OF Letter-disp '          '
                   'W : ' W-cnt OF Letter-disp.
           DISPLAY 'K : ' K-cnt OF Letter-disp '          '
                   'X : ' X-cnt OF Letter-disp.
           DISPLAY 'L : ' L-cnt OF Letter-disp '          '
                   'Y : ' Y-cnt OF Letter-disp.
           DISPLAY 'M : ' M-cnt OF Letter-disp '          '
                   'Z : ' Z-cnt OF Letter-disp.
           STOP RUN.
       
       
       END-PROGRAM.
Output:
Letter Frequency Distribution
-----------------------------
A :   416          N :   434
B :   120          O :   545
C :   316          P :   215
D :   267          Q :    12
E :   679          R :   436
F :   122          S :   432
G :   171          T :   493
H :   131          U :   180
I :   429          V :    57
J :    12          W :    97
K :    17          X :    35
L :   303          Y :    50
M :   162          Z :    60

Component Pascal

BlackBox Component Builder

MODULE LetterFrecuency;
IMPORT Files,StdLog,Strings;

PROCEDURE Do*;
VAR
	loc: Files.Locator;
	fd: Files.File;
	rd: Files.Reader;
	x: BYTE;
	frecuency: ARRAY 26 OF LONGINT;
	c: CHAR;
	i: INTEGER;
BEGIN
	loc := Files.dir.This("BBTest/Mod");
	fd := Files.dir.Old(loc,"LetterFrecuency.odc",FALSE);
	rd := fd.NewReader(NIL);
	
	(* init the frecuency array *)
	FOR i := 0 TO LEN(frecuency) - 1 DO frecuency[i] := 0 END;
	
	(* collect frecuencies *)
	WHILE ~rd.eof DO
		rd.ReadByte(x);c := CAP(CHR(x));
		(* convert vowels with diacritics *)
		CASE ORD(c) OF
			 193: c := 'A';
			|201: c := 'E';
			|205: c := 'I';
			|211: c := 'O';
			|218: c := 'U';
			ELSE
		END;
		IF (c >= 'A') & (c <= 'Z') THEN
			INC(frecuency[ORD(c) - ORD('A')]);
		END
	END;
	
	(* show data *)
	FOR i := 0 TO LEN(frecuency) - 1 DO
		StdLog.Char(CHR(i + ORD('A')));StdLog.String(":> ");StdLog.Int(frecuency[i]);
		StdLog.Ln
	END
END Do;
END LetterFrecuency.

Execute: ^Q LetterFrecuency.Do

Output:
A:>  28
B:>  7
C:>  100
D:>  94
E:>  168
F:>  30
G:>  10
H:>  11
I:>  49
J:>  0
K:>  1
L:>  67
M:>  25
N:>  57
O:>  81
P:>  3
Q:>  0
R:>  91
S:>  90
T:>  94
U:>  32
V:>  14
W:>  15
X:>  15
Y:>  17
Z:>  3

Cowgol

include "cowgol.coh";
include "argv.coh";
include "file.coh";

# Get filename from command line
ArgvInit();
var file := ArgvNext();
if file == (0 as [uint8]) then
    print("error: no file name\n");
    ExitWithError();
end if;

# Open the file
var fcb: FCB;
if FCBOpenIn(&fcb, file) != 0 then  
    print("error: cannot open file\n");
    ExitWithError();
end if;

# Counters for each letter
var letterCount: uint32[26];
MemZero(&letterCount as [uint8], @bytesof letterCount);

# Count every letter
var len := FCBExt(&fcb);
while len != 0 loop
    len := len - 1;
    var ch := (FCBGetChar(&fcb) | 32) - 'a';
    if ch >= @sizeof letterCount then
        continue;
    end if;
    letterCount[ch] := letterCount[ch] + 1;
end loop;

# Close the file
var foo := FCBClose(&fcb);

# Print value for each letter
ch := 0;
while ch < @sizeof letterCount loop
    print_char(ch + 'A');
    print(": ");
    print_i32(letterCount[ch]);
    print_nl();
    ch := ch + 1;
end loop;
Output:

The result of running the program on its own source file:

A: 22
B: 11
C: 46
D: 9
E: 80
F: 32
G: 6
H: 26
I: 42
J: 0
K: 0
L: 39
M: 7
N: 53
O: 45
P: 14
Q: 0
R: 47
S: 8
T: 59
U: 18
V: 11
W: 5
X: 4
Y: 2
Z: 3

D

void main() {
    import std.stdio, std.ascii, std.algorithm, std.range;

    uint[26] frequency;

    foreach (const buffer; "unixdict.txt".File.byChunk(2 ^^ 15))
        foreach (immutable c; buffer.filter!isAlpha)
            frequency[c.toLower - 'a']++;

    writefln("%(%(%s, %),\n%)", frequency[].chunks(10));
}
Output:
16421, 4115, 8216, 5799, 20144, 2662, 4129, 5208, 13980, 430,
1925, 10061, 5828, 12097, 12738, 5516, 378, 13436, 10210, 12836,
6489, 1902, 1968, 617, 3633, 433

Delphi

See Pascal.

Draco

proc nonrec main() void:
    file() infile;
    [256] char linebuf;
    [256] word count;
    *char line;
    char c;
    byte i;
    word n;
    channel input text filech;
    channel input text linech;
    
    for i from 0 upto 255 do count[i] := 0 od;
    line := &linebuf[0];
    
    open(filech, infile, "unixdict.txt");
    while readln(filech; line) do
        open(linech, line);
        while read(linech; c) do
            i := pretend(c, byte);
            count[i] := count[i] + 1
        od;
        close(linech)
    od;
    close(filech);
    
    for c from 'A' upto 'Z' do
        i := pretend(c, byte);
        n := count[i] + count[i | 32];
        writeln(c, pretend(i | 32, char), ": ", n:5)
    od
corp
Output:
Aa: 16421
Bb:  4115
Cc:  8216
Dd:  5799
Ee: 20144
Ff:  2662
Gg:  4129
Hh:  5208
Ii: 13980
Jj:   430
Kk:  1925
Ll: 10061
Mm:  5828
Nn: 12097
Oo: 12738
Pp:  5516
Qq:   378
Rr: 13436
Ss: 10210
Tt: 12836
Uu:  6489
Vv:  1902
Ww:  1968
Xx:   617
Yy:  3633
Zz:   433

EasyLang

len d[] 26
repeat
   s$ = input
   until s$ = ""
   for c$ in strchars s$
      c = strcode c$
      if c >= 97 and c <= 122
         c -= 32
      .
      if c >= 65 and c <= 91
         d[c - 64] += 1
      .
   .
.
for i to 26
   write strchar (96 + i) & ": "
   print d[i]
.
input_data
Open a text file and count the occurrences of each letter.
Some of these programs count all characters (including
punctuation), but some only count letters A to Z.
Other tasks related to string operations:


EchoLisp

We use a property list - plist for short - which is a hash table, to store the pairs ( letter . count) .

;; bump count when letter added
(define (hash-counter hash key )
		;; (set! key (string-downcase key)) - if ignore case wanted
		(putprop hash (1+ (or (getprop hash key) 0 )) key))
		
;;  apply to exploded string
;;  and sort result
(define (hash-compare a b) ( < (first a) (first b)))
(define (count-letters hash string)
		(map (curry hash-counter hash) (string->list string))
		(list-sort hash-compare (symbol-plist hash)))
Output:
(define (file-stats file string) 
	(set-plist! 'file-stats null) ; reset counters
	(writeln (count-letters 'file-stats string))
	(writeln "Total letters:" (string-length string))
	(writeln "Total lines:" (getprop 'file-stats "#\\newline")))

; frequency for 'help.html' file
(file->string file-stats) ; browser 'open' dialog

 help.html -> string
 (( 28918) (! 138) (# 1035) (#\newline 4539) (#\tab 409) ($ 7) (% 24) (& 136) (' 1643) ((3577) () 3583) (* 233)
 (+ 303) (, 599) (- 3164) (. 1454) (/ 5388) (0 1567) (1 1769) (2 1258) (3 857) (4 1872) (5 453) (6 581) (7 344) 
 (8 337) (9 411) (: 1235) (; 647) (< 9951) (= 1834) (> 10255) (? 392) (@ 11) (A 166) (B 92) (C 144) (D 72) (E 224)
 (F 52) (G 35) (H 42) (I 193) (J 31) (K 36) (L 196) (M 82) (N 94) (O 132) (P 192) (Q 27) (R 56) (S 220) (T 226) (U 37)
 (V 51) (W 28) (X 6) (Y 38) (Z 2) ([ 237) (\ 12) (] 215) (^ 28) (_ 107) (` 7) (a 8420) (b 4437) (c 3879) (d 4201) 
 (e 11905) (f 2989) (g 2068) (h 3856) (i 11313) (j 334) (k 653) (l 5748) (m 3048) (n 7020) (o 7207) (p 3585) (q 249)
 (r 8312) (s 8284) (t 8704) (u 3833) (v 1135) (w 861) (x 1172) (y 1451) (z 268) ({ 123) (| 62) (} 123) (~ 7) (§ 1) (© 1)
 (« 1) (» 1) (É 2) (à 18) (â 3) (ç 3) (è 6) (é 53) (î 1) (ö 9) (û 1) (œ 1) (ε 2) (λ 12) (μ 1) (ο 2) (ς 1)
 (τ 1) (а 1) (д 1) (е 1) (з 1) (л 1) (м 1) (н 1) (я 3) ( 1) ( 2) ( 2) ( 2) ( 184) ( 465) ( 57) ( 4) ( 1)
 ( 2) ( 6) ( 4)( 12) ( 2) ( 2) ( 1) ( 4) ( 1) ( 7) ( 2) ( 2) ( 6) ( 2) ( 8) ( 8) 
 ( 2) ( 1) ( 2) ( 1) ( 1) ( 1) ( 1) ( 1) ( 1) ( 1) ( 1) ( 1) ( 1) ( 1) ( 3) ( 1) 
 ( 1) ( 1) ( 900) ( 1) ( 2) ... )    
 Total letters:     212631    
 Total lines:     4539

Eiffel

class
	APPLICATION

create
	make

feature {NONE} -- Initialization

	make
			-- Read from the file and print frequencies.
		local
			file: PLAIN_TEXT_FILE
		do
			create file.make_open_read("input.txt")
			file.read_stream(file.count)
			file.close
			across get_frequencies(file.last_string) as f loop
				print(f.key.out + ": " + f.item.out + "%N")
			end
		end

feature -- Access

	get_frequencies (s: STRING): HASH_TABLE[INTEGER, CHARACTER]
			-- Hash table of counts for alphabetic characters in `s'.
		local
			char: CHARACTER
		do
			create Result.make(0)
			across s.area as st loop
				char := st.item
				if char.is_alpha then
					if Result.has(char) then
						Result.force(Result.at(char) + 1, char)
					else
						Result.put (1, char)
					end
				end
			end
		end
end
Output:

when file contains "Hello, Eiffel world!"

H: 1
e: 2
l: 4
o: 2
E: 1
i: 1
f: 2
w: 1
r: 1
d: 1

Elixir

file = hd(System.argv)

File.read!(file)
|> String.upcase
|> String.graphemes
|> Enum.filter(fn c -> c =~ ~r/[A-Z]/ end)
|> Enum.reduce(Map.new, fn c,acc -> Map.update(acc, c, 1, &(&1+1)) end)
|> Enum.sort_by(fn {_k,v} -> -v end)
|> Enum.each(fn {k,v} -> IO.puts "#{k}  #{v}" end)
Output:
C:\Elixir>elixir letterfrequency.exs \work\unixdict.txt
E  20144
A  16421
I  13980
R  13436
T  12836
O  12738
N  12097
S  10210
L  10061
C  8216
U  6489
M  5828
D  5799
P  5516
H  5208
G  4129
B  4115
Y  3633
F  2662
W  1968
K  1925
V  1902
X  617
Z  433
J  430
Q  378

Emacs Lisp

(defun tally-letter-frequency-in-file ()
  "Open a file and count the number of times each letter appears."
  (let ((alphabet "abcdefghijklmnopqrstuvwxyz")    ; variable to hold letters we will be counting
	(current-letter)                               ; variable to hold current letter we will be counting 
	(count)                                        ; variable to count how many times current letter appears
	(case-fold-search t))                          ; ignores case
    (find-file "~/Documents/Elisp/MobyDick.txt")   ; open file in a buffer (or switch to buffer if file is already open)
  (while (>= (length alphabet) 1)                  ; as long as there is at least 1 letter left in alphabet
    (beginning-of-buffer)                          ; go to the beginning of the buffer
    (setq current-letter (substring alphabet 0 1)) ; set current-letter to first letter of alphabet
    (setq count (how-many current-letter))         ; count how many of this letter in file
    (end-of-buffer)                                ; go to the end of the buffer 
    (insert (format "\n%s%s - %7d" current-letter (upcase current-letter) count))  ; write how many times that letter appears
    (setq alphabet (substring alphabet 1 nil)))    ; remove first letter from alphabet
(insert "\n")))
Output:

aA -   79220
bB -   17203
cC -   23318
dD -   38834
eE -  119345
fF -   21252
gG -   21287
hH -   63769
iI -   66671
jJ -    1176
kK -    8228
lL -   43349
mM -   23626
nN -   66778
oO -   70808
pP -   17873
qQ -    1581
rR -   53589
sS -   65136
tT -   89874
uU -   27205
vV -    8724
wW -   22556
xX -    1064
yY -   17242
zZ -     635


Erlang

%% Implemented by Arjun Sunel
-module(letter_frequency).
-export([main/0, letter_freq/1]).
main() ->
	case  file:read_file("file.txt") of
		{ok, FileData} ->
			letter_freq(binary_to_list(FileData));
		_FileNotExist ->
			io:format("File do not exist~n")
	end.
	
letter_freq(Data) ->
	lists:foreach(fun(Char) ->
					LetterCount = lists:foldl(fun(Element, Count) ->
											case Element =:= Char of
												true ->
													Count+1;
												false ->
													Count
											end		
										end, 0, Data),
						
					case LetterCount >0 of
						true ->					
							io:format("~p	:	~p~n", [[Char], LetterCount]);
						false ->
							io:format("")
					end		
				end,  lists:seq(0, 222)).
Output:
"\n"    :       5
" "     :       4
","     :       1
"."     :       22
":"     :       3
"M"     :       1
"a"     :       2
"e"     :       2
"i"     :       1
"j"     :       1
"l"     :       1
"m"     :       1
"n"     :       3
"r"     :       1
"s"     :       2
"u"     :       2
"y"     :       1
"}"     :       2
ok

Alternatively letter_freq/1 above can be replaced with

letter_freq( Data ) ->
	Dict = lists:foldl( fun (Char, Dict) -> dict:update_counter( Char, 1, Dict ) end, dict:new(), Data ),
	[io:fwrite( "~p	:	~p~n", [[X], dict:fetch(X, Dict)]) || X <- dict:fetch_keys(Dict)].

ERRE

Using ERRE help file for testing.

PROGRAM LETTER

DIM CNT[255]

BEGIN

      OPEN("I",1,"f:\errev30\erre.hlp")

      REPEAT
        GET(#1,A$)
        L%=LEN(A$)
        IF L%>0 THEN
          FOR I%=1 TO L% DO
            A%=ASC(MID$(A$,I%))
            CNT[A%]+=1
          END FOR
        END IF
      UNTIL EOF(1)
      CLOSE(1)

      FOR C%=$41 TO $5A DO
        PRINT(CHR$(C%);CHR$(C%+32);": ";CNT[C%]+CNT[C%+32])
      END FOR

END PROGRAM

Euphoria

Works with: OpenEuphoria
-- LetterFrequency.ex
-- Count frequency of each letter in own source code.

include std/console.e
include std/io.e
include std/text.e

sequence letters = repeat(0,26)

sequence content = read_file("LetterFrequency.ex")

content = lower(content)

for i = 1 to length(content) do
	if content[i] > 96 and content[i] < 123 then
		letters[content[i]-96] += 1
	end if
end for

for i = 1 to 26 do
	printf(1,"%s:  %d\n",{i+96,letters[i]})
end for

if getc(0) then end if
Output:
a: 4
b: 0
c: 21
-snip
x: 3
y: 3
z: 0

F#

let alphabet =
    ['A'..'Z'] |> Set.ofList

let letterFreq (text : string) =
    text.ToUpper().ToCharArray()
    |> Array.filter (fun x -> alphabet.Contains(x))
    |> Seq.countBy (fun x -> x)
    |> Seq.sort

let v = "Now is the time for all good men to come to the aid of the party"

let res = letterFreq v

for (letter, freq) in res do
    printfn "%A, %A" letter freq

Factor

USING: hashtables locals io assocs kernel io.encodings.utf8 io.files formatting ;
IN: count-letters

<PRIVATE

: count-from-stream ( -- counts )
  52 <hashtable>
  [ read1 dup ] [ over inc-at ] while
  drop ;

: print-counts ( counts -- )
  [ "%c: %d\n" printf ] assoc-each ;

PRIVATE>

: count-letters ( filename -- )
  utf8 [ count-from-stream ] with-file-reader
    print-counts ;

FBSL

The result of the first evaluation of ASC() is retained in the symbol ASC for later use. This is a standard feature of FBSL functions. The ascii array is dynamic. Command(1) is the name of the script file.

#APPTYPE CONSOLE

'Open a text file and count the occurrences of each letter.
FUNCTION countBytes(fileName AS STRING)
	DIM c AS STRING
	DIM ascii[]
	DIM handle AS INTEGER = FILEOPEN(fileName, BINARY)
	WHILE NOT FILEEOF(handle)
		c = FILEGETC(handle)
		IF c = "" THEN EXIT WHILE
		ascii[ASC] = ascii[ASC(c)] + 1
	WEND
	FILECLOSE(handle)
	RETURN ascii
END SUB

DIM counters = countBytes(COMMAND(1))
FOR DIM i = LBOUND(counters) TO UBOUND(counters)
	PRINT i, TAB, IIF(i <= 32, i, CHR(i)), TAB, counters[i]
NEXT

PAUSE

Forth

create counts 26 cells allot

: freq ( filename -- )
  counts 26 cells erase
  slurp-file bounds do
    i c@ 32 or [char] a -
    dup 0 26 within if
      cells counts +
      1 swap +!
    else drop then
  loop
  26 0 do
    cr [char] ' emit  [char] a i + emit  ." ': "
    counts i cells + @ .
  loop ;

s" example.txt" freq

Fortran

Using the configuration file (which has changed since the example was documented) of the J example, compilation and output of this program on a gnu/linux system is

-*- mode: compilation; default-directory: "/tmp/" -*-
Compilation started at Sat May 18 18:09:46

a=./F && make $a && $a < configuration.file
f95 -Wall -ffree-form F.F -o F
          92          21          17          24          82          19          19          22          67           0           2          27          27          57          55          31           1          61          43          60          20           6           2           0          10           0

Compilation finished at Sat May 18 18:09:46

And here's the FORTRAN90 program source. The program reads stdin and writes the result to stdout. Future enhancement: use block size records.

! count letters from stdin
program LetterFrequency
  implicit none
  character (len=1) :: s
  integer, dimension(26) :: a
  integer :: ios, i, t
  data a/26*0/,i/0/
  open(unit=7, file='/dev/stdin', access='direct', form='formatted', recl=1, status='old', iostat=ios)
  if (ios .ne. 0) then
    write(0,*)'Opening stdin failed'
    stop
  endif
  do i=1, huge(i)
    read(unit=7, rec = i, fmt = '(a)', iostat = ios ) s
    if (ios .ne. 0) then
      !write(0,*)'ios on failure is ',ios
      close(unit=7)
      exit
    endif
    t = ior(iachar(s(1:1)), 32) - iachar('a')
    if ((0 .le. t) .and. (t .le. iachar('z'))) then
      t = t+1
      a(t) = a(t) + 1
    endif
  end do
  write(6, *) a
end program LetterFrequency

FreeBASIC

' FB 1.05.0 Win64

Dim a(65 to 90) As Integer  ' array to hold frequency of each letter, all elements zero initially
Dim fileName As String = "input.txt"
Dim s As String
Dim i As Integer
Open fileName For Input As #1

While Not Eof(1)
  Line Input #1, s
  s = UCase(s)
  For i = 0 To Len(s) - 1
    a(s[i]) += 1
  Next
Wend

Close #1

Print "The frequency of each letter in the file "; fileName; " is as follows:"
Print
For i = 65 To 90
  If a(i) > 0 Then
    Print Chr(i); " : "; a(i)
  End If
Next
Print
Print "Press any key to quit"
Sleep
Output:
/'
   results for input.txt which contains the single line:
   The quick brown fox jumps over the lazy dog. 
'/

The frequency of each letter in the file input.txt is as follows:

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

Input:

This is the one question that most people ask. Why bother learning a completely different computing environment, when the operating 
system that ships with most desktops, laptops, and servers works just fine? To answer that question, I would pose another question. 
Does that operating system you’re currently using really work “just fine”? Or are you constantly battling viruses, malware, slow 
downs, crashes, costly repairs, and licensing fees?

If you struggle with the above, and want to free yourself from the constant fear of losing data or having to take your computer in 
for the “yearly clean up,” Linux might be the perfect platform for you. Linux has evolved into one of the most reliable computer 
ecosystems on the planet. Combine that reliability with zero cost of entry and you have the perfect solution for a desktop platform.

Frink

This example shows some of the subtle and non-obvious power of Frink in processing text files in a language-aware and Unicode-aware fashion:

  • Frink has a Unicode-aware function, graphemeList[str], which intelligently enumerates through what a human would consider to be a single visible character, including "characters" composed of multiple Unicode codepoints.
  • The file fetched from Project Gutenberg is supposed to be encoded in UTF-8 character encoding, but their servers incorrectly send either that it is Windows-1252 encoded or send no character encoding at all, so this program fixes that.
  • Frink has a Unicode-aware lowercase function, lc[str] that correctly handles accented characters and may even make a string longer.
  • This uses full Unicode tables to determine what is a "letter."
  • This works with high Unicode characters, that is above \uFFFF.
  • Frink can normalize Unicode characters with its normalizeUnicode function so the same grapheme encoded two different ways in Unicode can be treated consistently. For example, a Unicode string can use various methods to encode what is essentially the same character/glyph. For example, the character ô can be represented as either "\u00F4" or "\u006F\u0302". The former is a "precomposed" character, "LATIN SMALL LETTER O WITH CIRCUMFLEX", and the latter is two Unicode codepoints, an o (LATIN SMALL LETTER O) followed by "COMBINING CIRCUMFLEX ACCENT". (This is usually referred to as a "decomposed" representation.) Unicode normalization rules can convert these "equivalent" encodings into a canonical representation. This makes two different strings which look equivalent to a human (but are very different in their codepoints) be treated as the same to a computer, and these programs will count them the same. Even if the Project Gutenberg document uses precomposed and decomposed representations for the same characters, this program will fix it and count them the same! See the [Unicode Normal Forms] specification for more about these normalization rules. Frink implements all of them (NFC, NFD, NFKC, NFKD). NFC is the default in normalizeUnicode[str, encoding=NFC]. They're interesting!

How many other languages in this page do all or any of this correctly?

print[formatTable[countToArray[select[graphemeList[lc[normalizeUnicode[read["https://www.gutenberg.org/files/135/135-0.txt", "UTF-8"],"NFC"]]], %r/[[:alpha:]]/ ]] , "right"]]
Output:
e 330603
t 235571
a 207101
o 184385
h 176823
i 175320
n 169922
s 162043
r 148632
d 108724
l  99567
u  68295
c  67332
m  62212
w  56507
f  56187
g  48543
p  43366
y  39183
b  37461
v  26258
k  14427
j   5838
x   4026
q   2533
z   1905
é   1473
è    299
æ    116
ê     74
à     64
â     56
ç     50
ü     39
î     39
œ     38
ô     34
ù     18
ï     18
û      9
ë      5
ñ      2

FutureBasic

A clone of the Objective-C solution.

This code assumes a text file named "MyTextFile.txt" is in the same folder as the code file.

include "NSLog.incl"
include resources "MyTextFile.txt"

void local fn DoIt
  CFURLRef      url
  CFStringRef   string
  NSUInteger    length, index
  unichar       chr
  CountedSetRef set
  CFNumberRef   number
  
  url = fn BundleURLForResource( fn BundleMain, @"MyTextFile", @"txt", NULL )
  string = fn StringWithContentsOfURL( url, NSUTF8StringEncoding, NULL )
  if ( string )
    set = fn CountedSetWithCapacity(0)
    length = len(string)
    for index = 0 to length - 1
      chr = fn StringCharacterAtIndex( string, index )
      CountedSetAddObject( set, @(chr) )
    next    
    for number in set
      NSLog(@"%C = %ld",intVal(number),fn CountedSetCountForObject( set, number ))
    next
  end if
end fn

fn DoIt

HandleEvents

Gambas

Public Sub Form_Open()
Dim sData As String = File.Load("data.txt")
Dim iCount, iSpaces, iLetters, iOther As Integer
Dim bPunctuation As Boolean

For iCount = 1 To Len(sData)
  If InStr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", UCase(Mid(sData, iCount, 1))) Then 
    Inc iLetters
    bPunctuation = True
  End If
   If Mid(sData, icount, 1) = " " Then 
    Inc iSpaces
    bPunctuation = True
  End If 
  If bPunctuation = False Then Inc iOther
  bPunctuation = False
Next

Message("Text contains " & Len(sData) & " characters\n" & iLetters & " Letters\n" & iSpaces & " Spaces\n" & iOther & " Punctuation, newlines etc.")

End

Output:

Text contains 854 characters
677 Letters
135 Spaces
42 Punctuation, newlines etc.

Go

package main

import (
    "fmt"
    "io/ioutil"
    "sort"
    "unicode"
)

const file = "unixdict.txt"

func main() {
    bs, err := ioutil.ReadFile(file)
    if err != nil {
        fmt.Println(err)
        return
    }
    m := make(map[rune]int)
    for _, r := range string(bs) {
        m[r]++
    }
    // answer is now in m.  sort and format output:
    lfs := make(lfList, 0, len(m))
    for l, f := range m {
        lfs = append(lfs, &letterFreq{l, f})
    }
    sort.Sort(lfs)
    fmt.Println("file:", file)
    fmt.Println("letter  frequency")
    for _, lf := range lfs {
        if unicode.IsGraphic(lf.rune) {
            fmt.Printf("   %c    %7d\n", lf.rune, lf.freq)
        } else {
            fmt.Printf("%U  %7d\n", lf.rune, lf.freq)
        }
    }
}

type letterFreq struct {
    rune
    freq int
}
type lfList []*letterFreq

func (lfs lfList) Len() int { return len(lfs) }
func (lfs lfList) Less(i, j int) bool {
    switch fd := lfs[i].freq - lfs[j].freq; {
    case fd < 0:
        return false
    case fd > 0:
        return true
    }
    return lfs[i].rune < lfs[j].rune
}
func (lfs lfList) Swap(i, j int) {
    lfs[i], lfs[j] = lfs[j], lfs[i]
}
Output:
file: unixdict.txt
letter  frequency
U+000A    25104
   e      20144
   a      16421
   i      13980
   r      13436
   t      12836
   o      12738
   n      12097
   s      10210
   l      10061
   c       8216
   u       6489
   m       5828
   d       5799
   p       5516
   h       5208
   g       4129
   b       4115
   y       3633
   f       2662
   w       1968
   k       1925
   v       1902
   x        617
   z        433
   j        430
   q        378
   '        105
   &          6
   .          6
   1          2
   0          1
   2          1
   3          1
   4          1
   5          1
   6          1
   7          1
   8          1
   9          1

Groovy

def frequency = { it.inject([:]) { map, value -> map[value] = (map[value] ?: 0) + 1; map } }

frequency(new File('frequency.groovy').text).each { key, value ->
    println "'$key': $value"
}
Output:
'd': 1
'e': 19
'f': 4
' ': 29
'r': 5
'q': 3
'u': 8
[lines omitted]
'o': 2
'x': 1
'h': 1
'k': 2
'"': 2
'$': 2

Harbour

PROCEDURE Main()
   LOCAL s := hb_MemoRead( Left( __FILE__ , At( ".", __FILE__ )) +"prg")
   LOCAL c, n, i
   LOCAL a := {}
   
   FOR EACH c IN s
      IF Asc( c ) > 31
         AAdd( a, c )
      ENDIF
   NEXT
   a := ASort( a )
   i := 1
   WHILE i <= Len( a )
      c := a[i] ; n := 1
      i++
      IF i < Len(a) .AND. c == a[i]
         WHILE c == a[i]
            n++ ; i++
         END
      ENDIF
      ?? "'" + c + "'" + "=" + hb_NtoS( n ) + " "
   END

   RETURN
Output:

(counting the printable characters of its own source code)

' '=190 '"'=12 ' ' '=2 '('=10 ')'=10 '+'=12 ','=5 '.'=3 '1'=3 '3'=1 ':'=6 ';'=2 '<'=2 '='=12 
'>'=1 '?'=2 'A'=10 'C'=5 'D'=6 'E'=13 'F'=7 'H'=3 'I'=9 'L'=13 'M'=2 'N'=9 'O'=5 'P'=1 
'R'=6 'S'=2 'T'=2 'U'=2 'W'=2 'X'=1 '['=3 ']'=3 '_'=10 'a'=12 'b'=2 'c'=9 'd'=3 'e'=5 
'f'=1 'g'=1 'h'=2 'i'=11 'm'=1 'n'=7 'o'=3 'p'=1 'r'=2 's'=3 't'=5 'w'=1 '{'=1 '}'=1

Haskell

Short version:

import Data.List (group, sort)

main :: IO ()
main = interact (show . fmap ((,) . head <*> length) . group . sort

or, as an alternative to sorting and grouping the whole string, we could use some kind of container as the accumulator for a single fold, for example:

import Data.List (sortBy)
import qualified Data.Map.Strict as M
import Data.Ord (comparing)

charCounts :: String -> M.Map Char Int
charCounts = foldr (M.alter f) M.empty
  where
    f (Just x) = Just (succ x)
    f _ = Just 1

main :: IO ()
main =
  readFile "miserables.txt"
    >>= mapM_ print
      . sortBy
        (flip $ comparing snd)
      . M.toList
      . charCounts
Output:
(' ',516452)
('e',325769)
('t',222955)
('a',199774)
('o',180987)
('h',170234)
('n',166901)
('i',165221)
('s',157643)
('r',145136)
('d',106989)
('l',97091)
('\n',73828)
('u',67370)
('c',62760)
('m',56011)
('f',53438)
('w',53332)
(',',48784)
('g',46086)
('p',39958)
('y',37945)
('b',34313)
('.',30487)
('v',24058)
('\8364',21159)
('\226',21155)
('k',14110)
('T',12571)
('I',10067)
('A',7359)
('\339',7121)
('\157',7033)
('H',6605)
('M',6208)
(';',5885)
('E',4969)
('-',4775)
('C',4594)
('S',4404)
('x',3694)
('\8482',3633)
('!',3539)
('R',3535)
('P',3429)
('O',3401)
('j',3392)
('B',3193)
('W',3181)
('\8221',3071)
('N',3053)
('?',2976)
('F',2768)
('G',2512)
(':',2463)
('L',2452)
('J',2448)
('q',2398)
('\195',2296)
('V',2210)
('_',2068)
('z',1847)
('D',1758)
('\169',1328)
('Y',1238)
('U',900)
('1',732)
('8',412)
('X',333)
('K',323)
('\732',298)
('\168',294)
('3',254)
('2',242)
('0',212)
('5',208)
('*',179)
('(',172)
(')',172)
('4',170)
('\8240',146)
('6',143)
('7',140)
('Q',135)
('[',122)
(']',122)
('9',118)
('\166',107)
('\170',74)
('Z',59)
('\162',56)
('\167',48)
('\174',39)
('\197',38)
('"',37)
('\188',37)
('\8220',35)
('\180',34)
('|',24)
('\175',18)
('\185',18)
('/',12)
('\8224',10)
('\187',9)
('\'',8)
('+',5)
('\171',5)
('\710',5)
('\8217',3)
('$',2)
('\177',2)
('\8225',2)
('#',1)
('%',1)
('&',1)
('@',1)
('{',1)
('}',1)
('\189',1)
('\194',1)

Icon and Unicon

The example below counts (case insensitive) letters and was run on a version of this source file.

link printf

procedure main(A)
every PrintCount(CountLetters(!A))    
end

procedure CountLetters(fn)  #: Return case insensitive count of letters
   K := table(0)
   if f := open(fn,"r") then {
      every c := !map(|read(f)) do 
         if any(&lcase,c) then K[c] +:= 1
      close(f)
      return K
      }
   else write(&errout,"Unable to open file ",fn)
end

procedure PrintCount(T)    #: Print the letters 
every c := key(T) do
   printf("%s - %d\n",c,T[c])
end

printf.icn provides formatting

Output:
c - 17
k - 5
s - 10
h - 2
p - 10
e - 41
m - 2
u - 12
b - 2
r - 25
o - 16
w - 1
d - 10
l - 10
t - 27
a - 10
i - 13
y - 5
f - 12
n - 28
v - 4

Insitux

Works with the Node REPL.

(-> (read "README.md")
    (filter letter?)
    (map upper-case)
    freqs
    (sort-by 1)
    reverse
    (map (join " "))
    (join "  "))
Output:
E 2637  T 2238  R 1893  A 1880  N 1717  I 1676  O 1562  S 1469  L 1156  C 961  U 905  H 699  D 680  P 585  M 567  F 561  G 378  B 373  V 343  Y 324  X 263  W 220  K 134  Z 56  J 49  Q 18

IS-BASIC

100 PROGRAM "Letters.bas"
110 NUMERIC LETT(65 TO 90)
120 FOR I=65 TO 90
130   LET LETT(I)=0
140 NEXT
150 LET EOF=0
160 OPEN #1:"list.txt"
170 WHEN EXCEPTION USE IOERROR
180   DO
190     GET #1:A$
200     LET A$=UCASE$(A$)
210     IF A$>="A" AND A$<="Z" THEN LET LETT(ORD(A$))=LETT(ORD(A$))+1
220   LOOP UNTIL EOF
230 END WHEN 
240 FOR I=65 TO 90
250   PRINT CHR$(I);":";LETT(I),
260 NEXT 
270 HANDLER IOERROR
280   LET EOF=-1
290   CLOSE #1
300   CONTINUE
310 END HANDLER

J


Input is a directory-path with filename. Result is 26 integers representing counts of each letter, in alphabetic order (a's count is first).

ltrfreq=: 3 : 0
  letters=. u: 65 + i.26  NB. upper case letters
  <: #/.~ letters (, -. -.~) toupper fread y  
)

Example use (based on a configuration file from another task):

   ltrfreq 'config.file'
88 17 17 24 79 18 19 19 66 0 2 26 26 57 54 31 1 53 43 59 19 6 2 0 8 0

Java

This implementation will capture the frequency of all characters

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
public static void main(String[] args) throws IOException {
    Map<Integer, Integer> frequencies = frequencies("src/LetterFrequency.java");
    System.out.println(print(frequencies));
}

static String print(Map<Integer, Integer> frequencies) {
    StringBuilder string = new StringBuilder();
    int key;
    for (Map.Entry<Integer, Integer> entry : frequencies.entrySet()) {
        key = entry.getKey();
        string.append("%,-8d".formatted(entry.getValue()));
        /* display the hexadecimal value for non-printable characters */
        if ((key >= 0 && key < 32) || key == 127) {
            string.append("%02x%n".formatted(key));
        } else {
            string.append("%s%n".formatted((char) key));
        }
    }
    return string.toString();
}

static Map<Integer, Integer> frequencies(String path) throws IOException {
    try (InputStreamReader reader = new InputStreamReader(new FileInputStream(path))) {
        /* key = character, and value = occurrences */
        Map<Integer, Integer> map = new HashMap<>();
        int value;
        while ((value = reader.read()) != -1) {
            if (map.containsKey(value)) {
                map.put(value, map.get(value) + 1);
            } else {
                map.put(value, 1);
            }
        }
        return map;
    }
}
44      0a
463      
1       !
8       "
5       %
2       &
33      (
33      )
4       *
1       +
9       ,
3       -
29      .
5       /
2       0
4       1
3       2
1       3
1       7
1       8
1       :
19      ;
7       <
12      =
7       >
2       B
4       E
4       F
2       H
18      I
2       K
2       L
8       M
3       O
3       R
13      S
1       V
1       [
1       ]
73      a
3       b
28      c
19      d
121     e
13      f
25      g
11      h
53      i
6       j
8       k
25      l
22      m
67      n
24      o
44      p
8       q
81      r
30      s
87      t
34      u
15      v
7       w
5       x
20      y
11      {
2       |
11      }


Works with: Java version 5+
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;

public class LetterFreq {
	public static int[] countLetters(String filename) throws IOException{
		int[] freqs = new int[26];
		BufferedReader in = new BufferedReader(new FileReader(filename));
		String line;
		while((line = in.readLine()) != null){
			line = line.toUpperCase();
			for(char ch:line.toCharArray()){
				if(Character.isLetter(ch)){
					freqs[ch - 'A']++;
				}
			}
		}
		in.close();
		return freqs;
	}
	
	public static void main(String[] args) throws IOException{
		System.out.println(Arrays.toString(countLetters("filename.txt")));
	}
}
Works with: Java version 7+

In Java 7, we can use try with resources. The countLetters method would look like this:

public static int[] countLetters(String filename) throws IOException{
	int[] freqs = new int[26];
	try(BufferedReader in = new BufferedReader(new FileReader(filename))){
		String line;
		while((line = in.readLine()) != null){
			line = line.toUpperCase();
			for(char ch:line.toCharArray()){
				if(Character.isLetter(ch)){
					freqs[ch - 'A']++;
				}
			}
		}
	}
	return freqs;
}
Works with: Java version 8+

In Java 8, we can use streams. This code also handles unicode codepoints as well. The countLetters method would look like this:

public static Map<Integer, Long> countLetters(String filename) throws IOException {
    return Files.lines(Paths.get(filename))
        .flatMapToInt(String::chars)
        .filter(Character::isLetter)
        .boxed()
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}

JavaScript

ES5

JavaScript is no longer used only in environments which are carefully isolated from file systems, but JavaScript standards still do not specify standard file-system functions. Leaving aside the particular and variable details of how files will be opened and read in environments like Node.js and OS X JavaScript for Automation etc., we can still use core JavasScript (ES5 in the example below), to count the characters in a text once it has been read from a file system.

(function(txt) {

    var cs = txt.split(''),
        i = cs.length,
        dct =  {},
        c = '',
        keys;
        
    while (i--) {
        c = cs[i];
        dct[c] = (dct[c] || 0) + 1;
    }
    
    keys = Object.keys(dct);
    keys.sort();
    return keys.map(function (c) { return [c, dct[c]]; });

})("Not all that Mrs. Bennet, however, with the assistance of her five\
daughters, could ask on the subject, was sufficient to draw from her\
husband any satisfactory description of Mr. Bingley. They attacked him\
in various ways--with barefaced questions, ingenious suppositions, and\
distant surmises; but he eluded the skill of them all, and they were at\
last obliged to accept the second-hand intelligence of their neighbour,\
Lady Lucas. Her report was highly favourable. Sir William had been\
delighted with him. He was quite young, wonderfully handsome, extremely\
agreeable, and, to crown the whole, he meant to be at the next assembly\
with a large party. Nothing could be more delightful! To be fond of\
dancing was a certain step towards falling in love; and very lively\
hopes of Mr. Bingley's heart were entertained.");
Output:
[[" ", 121], ["!", 1], ["'", 1], [",", 13], ["-", 3], [".", 9], [";", 2], 
["B", 3], ["H", 2], ["L", 2], ["M", 3], ["N", 2], ["S", 1], ["T", 2], ["W", 1], 
["a", 53], ["b", 13], ["c", 17], ["d", 29], ["e", 82], ["f", 17], ["g", 16], ["h", 36],
["i", 44], ["j", 1], ["k", 3], ["l", 34], ["m", 11], ["n", 41], ["o", 40], ["p", 8], 
["q", 2], ["r", 35], ["s", 39], ["t", 55], ["u", 20], ["v", 7], ["w", 17], ["x", 2], ["y", 16]]

ES6

Using the 'JavaScript for Automation' embedding of a JSContext on macOS, for access to the file system:

(() => {
    'use strict';


    // charCounts :: String -> [(Char, Int)]
    const charCounts = s =>
        sortBy(flip(comparing(snd)))(
            Object.entries(
                chars(s).reduce(
                    (a, c) => (
                        a[c] = 1 + (a[c] || 0),
                        a
                    ), {}
                )
            )
        );

    // ----------------------- TEST -----------------------
    // main :: IO ()
    const main = () =>
        either(msg => msg)(
            compose(
                unlines,
                map(JSON.stringify),
                charCounts
            )
        )(readFileLR('~/Code/charCount/miserables.txt'));


    // -----------------GENERIC FUNCTIONS -----------------

    // Left :: a -> Either a b
    const Left = x => ({
        type: 'Either',
        Left: x
    });


    // Right :: b -> Either a b
    const Right = x => ({
        type: 'Either',
        Right: x
    });


    // chars :: String -> [Char]
    const chars = s =>
        s.split('');


    // comparing :: (a -> b) -> (a -> a -> Ordering)
    const comparing = f =>
        x => y => {
            const
                a = f(x),
                b = f(y);
            return a < b ? -1 : (a > b ? 1 : 0);
        };

    // compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
    const compose = (...fs) =>
        fs.reduce(
            (f, g) => x => f(g(x)),
            x => x
        );

    // either :: (a -> c) -> (b -> c) -> Either a b -> c
    const either = fl =>
        fr => e => 'Either' === e.type ? (
            undefined !== e.Left ? (
                fl(e.Left)
            ) : fr(e.Right)
        ) : undefined;


    // flip :: (a -> b -> c) -> b -> a -> c
    const flip = f =>
        1 < f.length ? (
            (a, b) => f(b, a)
        ) : (x => y => f(y)(x));


    // map :: (a -> b) -> [a] -> [b]
    const map = f =>
        // The list obtained by applying f
        // to each element of xs.
        // (The image of xs under f).
        xs => (
            Array.isArray(xs) ? (
                xs
            ) : xs.split('')
        ).map(f);


    // readFileLR :: FilePath -> Either String IO String
    const readFileLR = fp => {
        const
            e = $(),
            ns = $.NSString
            .stringWithContentsOfFileEncodingError(
                $(fp).stringByStandardizingPath,
                $.NSUTF8StringEncoding,
                e
            );
        return ns.isNil() ? (
            Left(ObjC.unwrap(e.localizedDescription))
        ) : Right(ObjC.unwrap(ns));
    };


    // snd :: (a, b) -> b
    const snd = tpl => tpl[1];


    // sortBy :: (a -> a -> Ordering) -> [a] -> [a]
    const sortBy = f =>
        xs => xs.slice()
        .sort((a, b) => f(a)(b));


    // unlines :: [String] -> String
    const unlines = xs =>
        // A single string formed by the intercalation
        // of a list of strings with the newline character.
        xs.join('\n');

    // MAIN ---
    return main();
})();
Output:
[" ",516452]
["e",325769]
["t",222955]
["a",199774]
["o",180987]
["h",170234]
["n",166901]
["i",165221]
["s",157643]
["r",145136]
["d",106989]
["l",97091]
["\n",73828]
["u",67370]
["c",62760]
["m",56011]
["f",53438]
["w",53332]
[",",48784]
["g",46086]
["p",39958]
["y",37945]
["b",34313]
[".",30487]
["v",24058]
["€",21159]
["â",21155]
["k",14110]
["T",12571]
["I",10067]
["A",7359]
["œ",7121]
["�",7033]
["H",6605]
["M",6208]
[";",5885]
["E",4969]
["-",4775]
["C",4594]
["S",4404]
["x",3694]
["™",3633]
["!",3539]
["R",3535]
["P",3429]
["O",3401]
["j",3392]
["B",3193]
["W",3181]
["”",3071]
["N",3053]
["?",2976]
["F",2768]
["G",2512]
[":",2463]
["L",2452]
["J",2448]
["q",2398]
["Ã",2296]
["V",2210]
["_",2068]
["z",1847]
["D",1758]
["©",1328]
["Y",1238]
["U",900]
["1",732]
["8",412]
["X",333]
["K",323]
["˜",298]
["¨",294]
["3",254]
["2",242]
["0",212]
["5",208]
["*",179]
["(",172]
[")",172]
["4",170]
["‰",146]
["6",143]
["7",140]
["Q",135]
["[",122]
["]",122]
["9",118]
["¦",107]
["ª",74]
["Z",59]
["¢",56]
["§",48]
["®",39]
["Å",38]
["¼",37]
["\"",37]
["“",35]
["´",34]
["|",24]
["¯",18]
["¹",18]
["/",12]
["†",10]
["»",9]
["'",8]
["ˆ",5]
["«",5]
["+",5]
["’",3]
["±",2]
["‡",2]
["$",2]
["#",1]
["&",1]
["Â",1]
["½",1]
["{",1]
["}",1]
["%",1]
["@",1]


Or, using an object as a hash-table, and the reduce method: (note that this version omits the opening of a text file which is specified in the task description):

(() => {
    'use strict';

    const letterfreq = text => [...text]
        .reduce(
            (a, c) => (a[c] = (a[c] || 0) + 1, a), 
            {}
        );

    return JSON.stringify(
        letterfreq(
            `remember, remember, the fifth of november
             gunpowder treason and plot
             I see no reason why gunpowder treason
             should ever be forgot`
        ),
        null, 2
    );
})();

Using the spread operator, you get the unicode characters rather than the UTF-16 code units.

Output:
{
  "r": 12,
  "e": 19,
  "m": 5,
  "b": 4,
  ",": 2,
  " ": 56,
  "t": 6,
  "h": 4,
  "f": 4,
  "i": 1,
  "o": 12,
  "n": 8,
  "v": 2,
  "\n": 3,
  "g": 3,
  "u": 3,
  "p": 3,
  "w": 3,
  "d": 4,
  "a": 4,
  "s": 5,
  "l": 2,
  "I": 1,
  "y": 1
}

jq

The following program will report the frequency of all characters in the input file, including newlines, returns, etc, provided the file will fit in memory.

# Input: an array of strings.
# Output: an object with the strings as keys,
# the values of which are the corresponding frequencies.
def counter:
  reduce .[] as $item ( {}; .[$item] += 1 ) ;

# For neatness we sort the keys:
explode | map( [.] | implode ) | counter | . as $counter
 | keys | sort[] | [., $counter[.] ]

Example:

jq -s -R -c -f Letter_frequency.jq somefile.txt
Output:
["\n",12]
[" ",124]
["#",1]
["$",8]
["(",4]
[")",4]
["+",3]
[",",4]
["-",4]
[".",9]
["0",3]
["1",7]
[":",2]
[";",2]
["=",4]
...

Julia

using DataStructures
 
function letterfreq(file::AbstractString; fltr::Function=(_) -> true)
    sort(Dict(counter(filter(fltr, read(file, String)))))
end
 
display(letterfreq("src/Letter_frequency.jl"; fltr=isletter))
Output:
DataStructures.OrderedDict{Char,Int64} with 29 entries:
  'A' => 1
  'C' => 1
  'D' => 2
  'F' => 1
  'L' => 3
  'S' => 2
  'a' => 9
  'b' => 1
  'c' => 13
  'd' => 5
  'e' => 30
  'f' => 13
  'g' => 4
  'h' => 10
  'i' => 14
  'j' => 1
  'k' => 3
  'l' => 11
  'n' => 15
  ⋮   => ⋮

K

+(?a;#:'=a:,/0:`)

Example: The file "hello.txt" contains the string "Hello, world!"

   
  c:+(?a;#:'=a:,/0:`hello.txt)
Output:
(("H";1)
 ("e";1)
 ("l";3)
 ("o";2)
 (",";1)
 (" ";1)
 ("w";1)
 ("r";1)
 ("d";1)
 ("!";1))

Sort on decreasing occurrences:

     c@>c[;1]
Output:
(("l";3)
 ("o";2)
 ("H";1)
 ("e";1)
 (",";1)
 (" ";1)
 ("w";1)
 ("r";1)
 ("d";1)
 ("!";1))

Kotlin

// version 1.1.2

import java.io.File

fun main(args: Array<String>) {
    val text = File("input.txt").readText().toLowerCase()
    val letterMap = text.filter { it in 'a'..'z' }.groupBy { it }.toSortedMap()
    for (letter in letterMap) println("${letter.key} = ${letter.value.size}")
    val sum = letterMap.values.sumBy { it.size }
    println("\nTotal letters = $sum")
}
Output:

'input.txt' just contains two pangrams:

The quick brown fox jumps over the lazy dog. Sphinx of black quartz, judge my vow.

a = 3
b = 2
c = 2
d = 2
e = 4
f = 2
g = 2
h = 3
i = 2
j = 2
k = 2
l = 2
m = 2
n = 2
o = 6
p = 2
q = 2
r = 3
s = 2
t = 3
u = 4
v = 2
w = 2
x = 2
y = 2
z = 2

Total letters = 64

Ksh

#!/bin/ksh

# Count the occurrences of each character

 ######
# main #
 ######

typeset -iA freqCnt
while read; do
	for ((i=0; i<${#REPLY}; i++)); do
		(( freqCnt[${REPLY:i:1}]++ ))
	done
done < $0		## Count chars of this code file

for ch in "${!freqCnt[@]}"; do
	[[ ${ch} == ?(\S) ]] && print -- "${ch}  ${freqCnt[${ch}]}"
done
Output:

Counts the characters of the source code file

!  2
"  4
#  19
$  8
&  2
(  5
)  5
+  4
-  3
/  2
0  2
1  1
:  2
;  5
<  2
=  3
?  1
@  1
A  1
C  6
E  2
L  2
P  2
R  2
S  1
Y  2
[  5
]  5
a  6
b  1
c  12
d  8
e  18
f  9
h  11
i  12
k  1
l  2
m  1
n  14
o  14
p  2
q  4
r  13
s  5
t  12
u  3
w  1
y  1
{  7

Lambdatalk

In this entry we choose to show how lambdatalk can use any existing javascript code (say the #Javascript entry in this page), and build an interface to use it as a standard lambdatalk function. So, applied to any string the W.frequency primitive returns a pair structure containing the array of chars and the corresponding array of frequencies.

{script  
// W.frequency is added to the lambdatalk dictionary via the {script ...} special form

LAMBDATALK.DICT['W.frequency'] = function() {     

// 1) simply copied from the rosetta.org #Javascript entry
  var frequency = function(txt) {
    var cs  = txt.split(''),
          i = cs.length,
        dct = {},
          c = '';
    while (i--) {
        c = cs[i];
        dct[c] = (dct[c] || 0) + 1;
    } 
    var keys = Object.keys(dct);
    keys.sort();
    return keys.map(function (c) { return [c, dct[c]]; });
  }; 

// 2) then interfaced with lambdatalk
  var args = arguments[0].trim().replace( /\s+/g, "␣" );

  var output = frequency( args );
 
  for (var a=[], b=[], i=0; i< output.length; i++) {
    a.push( output[i][0] );
    b.push( output[i][1] ); 
  }
  
  var pair = "{cons {A.new " + a.join(" ") + 
                 "} {A.new " + b.join(" ") + "}}"

  return LAMBDATALK.eval_forms( pair );
};
}

{def S3
Not all that Mrs. Bennet, however, with the assistance of her five daughters, could ask on the subject, was sufficient to draw from her husband any satisfactory description of Mr. Bingley. They attacked him in various ways--with barefaced questions, ingenious suppositions, and distant surmises; but he eluded the skill of them all, and they were at last obliged to accept the second-hand intelligence of their neighbour, Lady Lucas. Her report was highly favourable. Sir William had been delighted with him. He was quite young, wonderfully handsome, extremely agreeable, and, to crown the whole, he meant to be at the next assembly with a large party. Nothing could be more delightful! To be fond of dancing was a certain step towards falling in love; and very lively hopes of Mr. Bingley's heart were entertained.
}
-> S3
{def S3.freq {W.frequency {S3}}}
-> S3.freq

characters:  {car {S3.freq}} 
->  [!,',,,-,.,;,B,H,L,M,N,S,T,W,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,␣]

frequencies: {cdr {S3.freq}} 
-> [1,1,13,3,9,2,3,2,2,3,2,1,2,1,53,13,17,29,82,17,16,36,44,1,3,34,11,41,40,8,2,35,39,55,20,7,17,2,16,132]
}

langur

val .countLetters = fn(.s) {
    for[=h{}] .s2 in split(replace(.s, RE/\P{L}/)) {
        _for[.s2; 0] += 1
    }
}

val .counts = .countLetters(readfile "./fuzz.txt")
writeln join "\n", map fn(.k) $"\.k;: \.counts[.k];", keys .counts
Output:

The input contains "fuzzy furry kittens ασδ ξκλ ασδ ξα" (random Greek letters at the end) and the output is as follows.

f: 2
u: 2
z: 2
y: 2
r: 2
k: 1
i: 1
t: 2
e: 1
n: 1
s: 1
α: 3
σ: 2
δ: 2
ξ: 2
κ: 1
λ: 1

Lasso

local(
	str 	= 'Hello world!',
	freq	= map
)
// as a loop. arguably quicker than query expression
loop(#str->size) => {
	#freq->keys !>> #str->get(loop_count) ? 
		#freq->insert(#str->get(loop_count) = #str->values->find(#str->get(loop_count))->size)
}

// or
local(
	str 	= 'Hello world!',
	freq	= map
)
// as query expression, less code
with i in #str->values where #freq->keys !>> #i do => {
	#freq->insert(#i = #str->values->find(#i)->size)
}

// output #freq
with elem in #freq->keys do => {^
	'"'+#elem+'": '+#freq->find(#elem)+'\r'
^}

Liberty BASIC

Un-rem a line to convert to all-upper-case. Letter freq'y is printed as percentages.

    open "text.txt" for input as #i
        txt$ =input$( #i, lof( #i))
        Le =len( txt$)
    close #i

    dim LetterFreqy( 255)

    '   txt$ =upper$( txt$)

    for i =1 to Le
        char =asc( mid$( txt$, i, 1))
        if char >=32 then LetterFreqy( char) =LetterFreqy( char) +1
    next i

    for j =32 to 255
        if LetterFreqy( j) <>0 then print " Character #"; j, "("; chr$( j);_
         ") appeared "; using( "##.##", 100 *LetterFreqy( j) /Le); "% of the time."
    next j

    end

Lua

This solution counts letters only, which could be changed by altering the pattern argument to 'gmatch' on line 31. It also treats upper and lower case letters as distinct, which could be changed by changing everything to upper or lower case with string.upper() or string.lower() before tallying.

-- Return entire contents of named file
function readFile (filename)
  local file = assert(io.open(filename, "r"))
  local contents = file:read("*all")
  file:close()
  return contents
end

-- Return a closure to keep track of letter counts
function tally ()
  local t = {}
  
  -- Add x to tally if supplied, return tally list otherwise
  local function count (x)
    if x then
      if t[x] then
        t[x] = t[x] + 1
      else
        t[x] = 1
      end
    else
      return t
    end
  end
  
  return count
end

-- Main procedure
local letterCount = tally()
for letter in readFile(arg[1] or arg[0]):gmatch("%a") do
  letterCount(letter)
end
for k, v in pairs(letterCount()) do
  print(k, v)
end

Output from running this script on itself:

i       24
f       16
R       2
v       2
c       19
k       4
M       1
s       14
d       17
l       40
e       61
t       54
m       4
r       34
u       18
C       3
o       32
A       1
g       3
x       7
F       2
y       4
w       1
n       42
h       4
a       25
p       7

M2000 Interpreter

document file1$={Open a text file and count the occurrences of each letter.
		Some of these programs count all characters (including punctuation), but some only count letters A to Z
		}
const Ansi=3, nl$=chr$(13)+chr$(10), Console=-2
save.doc file1$, "checkdoc.txt", Ansi
open "checkdoc.txt" for input as F
buffer onechar as byte
m=0
dim m(65 to 90)
while not eof(#F)
	get #F, onechar
	a$=chr$(eval(onechar,0))
	if a$ ~ "[A-Za-z]" then
		m++
		m(asc(ucase$(a$)))++
	end if
end while
close #F
document Export$
for i=65 to 90
	if m(i)>0 then Export$=format$("{0} - {1:2:4}%",chr$(i),m(i)/m*100)+nl$
next
print #Console, Export$
clipboard Export$
Output:
A - 6,87%
B - 0,76%
C - 8,40%
D - 1,53%
E - 12,2%
F - 2,29%
G - 1,53%
H - 3,05%
I - 3,05%
L - 5,34%
M - 2,29%
N - 8,40%
O - 9,92%
P - 2,29%
R - 6,11%
S - 5,34%
T - 12,2%
U - 6,11%
X - 0,76%
Y - 0,76%
Z - 0,76%

Maple

StringTools:-CharacterFrequencies(readbytes("File.txt",infinity,TEXT))

Mathematica / Wolfram Language

Tally[Characters[Import["file.txt","Text"]]]

MATLAB / Octave

function u = letter_frequency(t)
	if ischar(t)
		t = abs(t);
	end; 
	A = sparse(t+1,1,1,256,1);
	printf('"%c":%i\n',[find(A)-1,A(A>0)]')
end

Nanoquery

// define a list to hold characters and amounts
characters = list()
amounts = list()
 
// define the alphabet as a string to check only letters and numbers
alpha = "abcdefghijklmnopqrstuvwxyz0123456789"
 
// get the filename as an argument
fname = args[len(args) - 1]
 
// read the entire file into a string
contents = new(Nanoquery.IO.File, fname).readAll()
 
// loop through all the characters in the array
for i in range(0, len(contents) - 1)
	// get the character to check
	toCheck = str(contents[i]).toLowerCase()
 
	// check if the current character is in the array
	if ((alpha .contains. toCheck) && (characters .contains. toCheck))
		// if it's there, increment its amount
		index = characters[toCheck]
		amounts[index] = amounts[index] + 1
	else
		if (alpha .contains. toCheck)
			// if it's not, add it
			append characters toCheck
			append amounts 0
		end
	end if
end for
 
// output the amounts
println format("%-20s %s", "Character", "Amount")
println "=" * 30
for i in range(0, len(characters) - 1)
	println format("%-20s %d", characters[i], amounts[i])
end for
Output:
$ java -jar ../nanoquery-2.3_1462.jar -b letterfreq.nq sherlock-holmes.txt
Character            Amount
==============================
p                    7239
r                    25708
o                    34866
j                    544
e                    54972
c                    11118
t                    40545
g                    8311
u                    13604
n                    29701
b                    6645
s                    27941
h                    29588
a                    36146
d                    19064
v                    4567
f                    9362
l                    17633
k                    3684
m                    12150
y                    9776
i                    31240
w                    11554
2                    45
9                    23
0                    104
1                    127
6                    30
8                    46
z                    152
x                    578
q                    437
5                    27
4                    29
7                    25
3                    25

NetRexx

Translation of: REXX
/* NetRexx ************************************************************
* 22.05.2013 Walter Pachl  translated from REXX
**********************************************************************/
options replace format comments java crossref symbols nobinary

  parse arg dsn .
  if dsn = '' then
    dsn = 'test.txt'
  cnt=0
  totChars=0                         /*count of the total num of chars*/
  totLetters=0                       /*count of the total num letters.*/
  indent=' '.left(20)                /*used for indentation of output.*/
  lines = scanFile(dsn)
  loop l_ = 1 to lines[0]
    line = lines[l_]

    Say '>'line'<' line.length       /* that's in test.txt            */
    /*
    lrx=left_right(line)
    Parse lrx leftx rightx
    Say ' 'leftx
    Say ' 'rightx
    */
    loop k=1 for line.length()       /*loop over characters           */
      totChars=totChars+1            /*Increment total number of chars*/
      c=line.substr(k,1)             /*get character number k         */
      cnt[c]=cnt[c]+1                /*increment the character's count*/
      End
    end l_

  w=totChars.length                  /*used for right-aligning counts.*/
  say 'file -----' dsn "----- has" lines[0] 'records.'
  say 'file -----' dsn "----- has" totChars 'characters.'
  Loop L=0 to 255                    /* display nonzero letter counts */
    c=l.d2c                          /* the character in question     */
    if cnt[c]>0 & c.datatype('M')>0 Then Do /* was found in the file  */
                                     /* and is a latin letter         */
      say indent "(Latin) letter " c 'count:' cnt[c].right(w) /* tell */
      totLetters=totLetters+cnt[c]   /* increment number of letters   */
      End
    End

  say 'file -----' dsn "----- has" totLetters '(Latin) letters.'
  say '                           other charactes follow'
  other=0
  loop m=0 to 255                    /* now for non-letters           */
    c=m.d2c                          /* the character in question     */
    y=c.c2x                          /* the hex representation        */
    if cnt[c]>0 & c.datatype('M')=0 Then Do /* was found in the file  */
                                     /* and is not a latin letter     */
      other=other+cnt[c]             /* increment count               */
      _=cnt[c].right(w)              /* prepare output of count       */
      select                         /*make the character viewable.   */
       when c<<' ' | m==255 then say indent "'"y"'x character count:" _
       when c==' '          then say indent "blank character count:" _
       otherwise                 say indent "   " c 'character count:' _
       end
     end
   end
  say 'file -----' dsn "----- has" other 'other characters.'
  say 'file -----' dsn "----- has" totLetters 'letters.'

-- Read a file and return contents as a Rexx indexed string
method scanFile(dsn) public static returns Rexx

  fileLines = ''
  do
    inFile = File(dsn)
    inFileScanner = Scanner(inFile)
    loop l_ = 1 while inFileScanner.hasNext()
      fileLines[0] = l_
      fileLines[l_] = inFileScanner.nextLine()
      end l_
    inFileScanner.close()

  catch ex = FileNotFoundException
    ex.printStackTrace
  end

  return fileLines

Nim

import tables, os

var t = initCountTable[char]()
for l in paramStr(1).lines:
  for c in l:
    t.inc(c)
echo t

Objeck

use IO;

bundle Default {
  class Test {
    function : Main(args : String[]) ~ Nil {
      freqs := CountLetters("filename.txt");
      for(i := 'A'; i < 'Z'; i += 1;) {
        Console->Print(i->As(Char))->Print("=>")->PrintLine(freqs[i - 'A']);
      };
    }
    
    function : CountLetters(filename : String) ~ Int[] {
      freqs := Int->New[26];
      reader := FileReader->New(filename);
      while(reader->IsEOF() <> true) {
        line := reader->ReadString()->ToUpper();
        each(i : line) {
          ch := line->Get(i);
          if(ch->IsChar()){
            index := ch - 'A';
            freqs[index] := freqs[index] + 1;
          };
        };
      };
      reader->Close();
      
      return freqs;
    }
  }
}

Objective-C

#import <Foundation/Foundation.h>

int main (int argc, const char *argv[]) {
  @autoreleasepool {

    NSData *data = [NSData dataWithContentsOfFile:@(argv[1])];
    NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSCountedSet *countedSet = [[NSCountedSet alloc] init];
    NSUInteger len = [string length];
    for (NSUInteger i = 0; i < len; i++) {
      unichar c = [string characterAtIndex:i];
      if ([[NSCharacterSet letterCharacterSet] characterIsMember:c])
        [countedSet addObject:@(c)];
    }
    for (NSNumber *chr in countedSet) {
      NSLog(@"%C => %lu", (unichar)[chr integerValue], [countedSet countForObject:chr]);
    }
  
  }
  return 0;
}

OCaml

We open a text file and compute letter frequency. Other characters than [a-z] and [A-Z] are ignored, and upper case letters are first converted to lower case before to compute letter frequency.

let () =
  let ic = open_in Sys.argv.(1) in
  let base = int_of_char 'a' in
  let arr = Array.make 26 0 in
  try while true do
    let c = Char.lowercase(input_char ic) in
    let ndx = int_of_char c - base in
    if ndx < 26 && ndx >= 0 then
      arr.(ndx) <- succ arr.(ndx)
  done
  with End_of_file ->
    close_in ic;
    for i=0 to 25 do
      Printf.printf "%c -> %d\n" (char_of_int(i + base)) arr.(i)
    done

If we want to compute all characters in an UTF8 file, we must use an external library, for example Batteries. The following function takes as input a string that contains the path to the file, and prints all the characters together with their frequencies, ordered by increasing frequencies, on the standard output.

open Batteries

let frequency file = 
  let freq = Hashtbl.create 52 in
    File.with_file_in file
      (Enum.iter (fun c -> Hashtbl.modify_def 1 c succ freq) % Text.chars_of);
    List.iter (fun (k,v) -> Text.write_text stdout k; 
                            Printf.printf " %d\n" v)
    @@ List.sort (fun (_,v) (_,v') -> compare v v')
    @@ Hashtbl.fold (fun k v l -> (Text.of_uchar k,v) :: l) freq []

Ol

(define source (bytes->string (file->bytestream "letter_frequency.scm"))) ; utf-8
(define dict (lfold (lambda (ff char)
                     (put ff char (+ 1 (get ff char 0))))
               {}
               (str-iter source)))
; that's all.

; just print the dictionary in human readable format:
(for-each (lambda (kv)
            (let* ((key value kv))
               (case key
                  (#\newline
                     (display "NEWLINE"))
                  (#\tab
                     (display "TAB"))
                  (#\space
                     (display "SPACE"))
                  ((< key #\space) => (lambda (_)
                     (display "char ") (display key)))
                  (else
                     (display (string key))))
               (display " --> ")
               (display value))
            (print))
   (ff->alist dict))
Output:
NEWLINE --> 27
SPACE --> 374
" --> 12
# --> 5
' --> 1
( --> 37
) --> 37
* --> 1
+ --> 1
- --> 8
. --> 3
/ --> 4
0 --> 1
1 --> 1
8 --> 1
: --> 2
; --> 4
< --> 1
= --> 1
> --> 5
A --> 2
B --> 1
C --> 1
E --> 3
I --> 1
L --> 2
N --> 2
O --> 1
P --> 1
S --> 1
T --> 1
W --> 1
\ --> 4
_ --> 3
a --> 35
b --> 7
c --> 17
d --> 19
e --> 41
f --> 17
g --> 4
h --> 9
i --> 25
j --> 1
k --> 8
l --> 25
m --> 7
n --> 13
o --> 9
p --> 14
q --> 2
r --> 23
s --> 24
t --> 31
u --> 10
v --> 4
w --> 2
y --> 18
{ --> 1
} --> 1

OxygenBasic

indexbase 0

sys a,e,i,c[255]

string s=getfile "t.txt"

e=len s

for i=1 to e
  a=asc(s,i)
  ++c(a)
next

cr=chr(13)+chr(10)
pr="Char Frequencies" cr cr
for i=32 to 255
  pr+=chr(i) chr(9) c(i) cr
next

print pr
'putfile "CharCount.txt",pr

PARI/GP

v=vector(26);
U=readvec("foo.txt");
for(i=1,#U,u=Vecsmall(U[i]);for(j=1,#u,if(u[j]>64&&u[j]<91,v[u[j]-64]++,u[j]>96&&u[j]<123,v[u[j]-96]++)));
v

Pascal

Works with: Extended Pascal
program letterFrequency(input, output);
var
	chart: array[char] of 0..maxInt value [otherwise 0];
	c: char;
begin
	{ parameter-less EOF checks for EOF(input) }
	while not EOF do
	begin
		read(c);
		chart[c] := chart[c] + 1
	end;
	
	{ now, chart[someLetter] gives you the letter’s frequency }
end.

Perl

Counts letters in files given on command line or piped to stdin. Case insensitive.

while (<>) { $cnt{lc chop}++ while length }
print "$_: ", $cnt{$_}//0, "\n" for 'a' .. 'z';

Phix

Counts own source or supplied filename Now counts words in unixdict.txt of 17 letters or more (to make it js compatible)

with javascript_semantics
sequence lc = repeat(0,#7E)
--string text = get_text(command_line()[$])
string text = join(unix_dict(17))
for i=1 to length(text) do
    integer ch = text[i]
    if ch=-1 then exit end if
    if ch>=' ' and ch<#7F then
        lc[ch] += 1
    end if
end for
 
integer count = 0
for i=' ' to #7E do
    if lc[i]!=0 then
        count = mod(count+1,10)
        printf(1,"'%c': %-2d%s",{i,lc[i],iff(count=0?"\n":"  ")})
    end if
end for
Output:
' ': 14  'a': 15  'b': 2   'c': 20  'd': 7   'e': 33  'g': 7   'h': 16  'i': 22  'l': 16
'm': 5   'n': 14  'o': 27  'p': 15  'r': 26  's': 15  't': 24  'u': 6   'v': 1   'y': 4

Phixmonti

0 255 repeat var ascCodes

"unixdict.txt" "r" fopen var file

file 0 < not
if
	true
	while 
		file fgets
		dup 0 < not
		if
			len 1 swap 2 tolist
			for
				var i
				i get ascCodes over get 1 + rot set var ascCodes 
			endfor
			drop
			true
		else
			drop
			false
		endif
	endwhile

	ascCodes len
	for
		var i
		i get
		if
			i tochar print " = " print i get print nl
		endif
	endfor
	file fclose
endif

PHP

<?php
print_r(array_count_values(str_split(file_get_contents($argv[1]))));
?>

Picat

Sorting on the frequency (decreasing).

go =>
  % removing '\n' first
  Chars = delete_all(read_file_chars("unixdict.txt"),'\n'),
  M = letter_freq(Chars),
  println(M.sort_map(values).reverse).

% Get the letter frequency
letter_freq(S) = Map =>
  Map = new_map(),
  foreach(C in S)
    Map.put(C,Map.get(C,0)+1)
  end.

% Different sorting function on maps
sort_map(Map,values) = [K=V:_=(K=V) in sort([V=(K=V): K=V in Map])].
sort_map(Map,keys)   = sort([KV : KV in Map]).
sort_map(Map)        = sort_map(Map,keys).
Output:
[e = 20144,a = 16421,i = 13980,r = 13436,t = 12836,o = 12738,n = 12097,s = 10210,
 l = 10061,c = 8216,u = 6489,m = 5828,d = 5799,p = 5516,h = 5208,g = 4129,b = 4115,
 y = 3633,f = 2662,w = 1968,k = 1925,v = 1902,x = 617,z = 433,j = 430,q = 378,
 ' = 105,. = 6,& = 6,1 = 2,9 = 1,8 = 1,7 = 1,6 = 1,5 = 1,4 = 1,3 = 1,2 = 1,0 = 1]

PicoLisp

(let Freq NIL
   (in "file.txt"
      (while (char) (accu 'Freq @ 1)) )
   (sort Freq) )

For a "file.txt":

abcd
cdef
Output:
-> (("^J" . 2) ("a" . 1) ("b" . 1) ("c" . 2) ("d" . 2) ("e" . 1) ("f" . 1))

Pike

string all = Stdio.read_file("README.md");
mapping res = ([]);
foreach(all/1, string char)
    res[char]++;
write("%O\n", res);
Output:
([ /* 26 elements */
  "\n": 2,
  " ": 12,
  ".": 2,
  "/": 3,
  ":": 1,
  "P": 1,
  "T": 1,
  "a": 5,
  "c": 1,
  "d": 2,
  "e": 10,
  "f": 3,
  "g": 1,
  "h": 2,
  "i": 5,
  "k": 1,
  "l": 4,
  "m": 3,
  "n": 1,
  "o": 7,
  "p": 4,
  "r": 4,
  "s": 10,
  "t": 5,
  "u": 2,
  "x": 2
])

PL/I

frequencies: procedure options (main);
   declare tallies(26) fixed binary static initial ((26) 0);
   declare alphabet character (26) static initial
      ('ABCDEFGHIJKLMNOPQRSTUVWXYZ');
   declare c character (1), i fixed binary;
   declare in file;

   open file (in) title ('/LETTER.DAT,type(text),recsize(200)') input;

   on endfile (in) go to prepare_list;

   do while('1'b);
      get file (in) edit (c) (a(1)); put edit (c) (a);
      i = index(alphabet, c);
      if i > 0 then tallies(i) = tallies(i) + 1;
   end;

prepare_list:
   put skip list('Letter', 'Frequency');
   do i = 1 to 26;
      if tallies(i) > 0 then
         put skip list (substr(alphabet, i, 1), tallies(i));
   end;
end frequencies;

Data:

THEQUICKBROWNFOX
JUMPSOVERTHELAZYDOG
Output:
Letter                  Frequency 
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

PowerShell

function frequency ($string) {
    $arr = $string.ToUpper().ToCharArray() |where{$_ -match '[A-KL-Z]'} 
    $n = $arr.count
    $arr | group | foreach{
        [pscustomobject]@{letter = "$($_.name)"; frequency  = "$([math]::round($($_.Count/$n),5))"; count = "$($_.count)"}
    } | sort letter
}
$file = "$($MyInvocation.MyCommand.Name )" #Put the name of your file here
frequency $(get-content $file -Raw)

Output:

letter frequency count
------ --------- -----
A      0.06809   16   
B      0.00426   1    
C      0.06809   16   
D      0.00851   2    
E      0.11064   26   
F      0.0383    9    
G      0.01702   4    
H      0.02979   7    
I      0.03404   8    
J      0.00426   1    
K      0.00426   1    
L      0.02553   6    
M      0.04255   10   
N      0.09362   22   
O      0.08085   19   
P      0.02128   5    
Q      0.01277   3    
R      0.10638   25   
S      0.02128   5    
T      0.10213   24   
U      0.05957   14   
V      0.00426   1    
W      0.00851   2    
Y      0.02979   7    
Z      0.00426   1 

Prolog

Works with SWI-Prolog.
Only alphabetic codes are computed in uppercase state.
Uses packlist/2 defined there : Run-length encoding#Prolog

frequency(File) :-
	read_file_to_codes(File, Code, []),

	% we only keep alphabetic codes
	include(my_code_type, Code, LstCharCode),

	% we translate char_codes into uppercase atoms.
	maplist(my_upcase, LstCharCode, LstChar),

	% sort and pack the list
	msort(LstChar, SortLstChar),
	packList(SortLstChar, Freq),
	maplist(my_write, Freq).


my_write([Num, Atom]) :-
	swritef(A, '%3r', [Num]),
	writef('Number of %w :%w\n', [Atom, A]).


my_code_type(Code) :-
	code_type(Code, alpha).

my_upcase(CharCode, UpChar) :-
	char_code(Atom, CharCode),
	upcase_atom(Atom, UpChar).

:- use_module(library(clpfd)).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ?- packList([a,a,a,b,c,c,c,d,d,e], L).
%  L = [[3,a],[1,b],[3,c],[2,d],[1,e]] .
%
% ?- packList(R,  [[3,a],[1,b],[3,c],[2,d],[1,e]]).
% R = [a,a,a,b,c,c,c,d,d,e] .
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
packList([],[]).

packList([X],[[1,X]]) :-
	!.

packList([X|Rest],[XRun|Packed]):-
	run(X,Rest, XRun,RRest),
	packList(RRest,Packed).

run(Var,[],[1,Var],[]).

run(Var,[Var|LRest],[N1, Var],RRest):-
	N #> 0,
	N1 #= N + 1,
	run(Var,LRest,[N, Var],RRest).

run(Var,[Other|RRest], [1,Var],[Other|RRest]):-
	dif(Var,Other).
Output:

for this file

Number of A : 63
Number of B :  7
Number of C : 53
Number of D : 29
Number of E : 65
...
Number of T : 52
Number of U : 20
Number of V : 10
Number of W :  8
Number of X :  6
Number of Y : 12
true .

PureBasic

Alphabetic codes are converted to uppercase before being used and no other codes are used as part of the calculations.

Procedure countLetters(Array letterCounts(1), textLine.s)
  ;counts only letters A -> Z, uses index 0 of letterCounts() to keep a total of all counts
  Protected i, lineLength = Len(textLine), letter
  
  textLine = UCase(textLine)
  For i = 1 To lineLength
    letter = Asc(Mid(textLine, i, 1)) - 'A' + 1
    If letter >= 1 And letter <= 26
      letterCounts(letter) + 1 ;tally individual letter count
      letterCounts(0) + 1      ;increment total letter count
    EndIf
  Next
EndProcedure
 
If OpenConsole()
  Define filename.s, fileID, i
  filename = OpenFileRequester("Select text file to examine", "*.txt", "Text (*.txt)|*.txt;|All files (*.*)|*.*", 0)
  fileID = 0
  If ReadFile(fileID, filename)
    Dim letterCounts(26) ;A - Z only, index 0 contains the total of all letter counts
    
    Define textLine.s
    While Not Eof(fileID)
      textLine = ReadString(fileID)
      countLetters(letterCounts(), textLine)
    Wend
    CloseFile(fileID)
    
    PrintN("File: " + filename + #CRLF$)
    PrintN("Letter  %Freq  Count")
    For i = 1 To 26
      Print("  " + Chr(64 + i) + "     ")
      Print(RSet(StrF(100 * letterCounts(i) / letterCounts(0), 1), 5, " ") + "  ")
      PrintN(Str(letterCounts(i)))
    Next 
    PrintN(#CRLF$ + "Total letter count in file: " + Str(letterCounts(0)))
  EndIf 
  
  Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
  CloseConsole()
EndIf
Output:
File: D:\_T\Text\dictionary.txt

Letter  %Freq  Count
  A       7.6  27743
  B       2.0  7248
  C       4.3  15433
  D       3.8  13798
  E      11.8  42917
  F       1.4  5030
  G       2.8  10336
  H       2.1  7720
  I       8.6  31141
  J       0.2  588
  K       0.8  2964
  L       5.3  19399
  M       2.7  9821
  N       7.1  25682
  O       6.1  22084
  P       2.9  10696
  Q       0.2  714
  R       7.5  27055
  S       8.0  28898
  T       7.1  25773
  U       3.3  12032
  V       1.1  4019
  W       0.9  3348
  X       0.3  1096
  Y       1.7  6251
  Z       0.3  1177

Total letter count in file: 362963

Python

Functional

Using collections.Counter

Works with: Python version 2.7+ and 3.1+
import collections, sys

def filecharcount(openfile):
    return sorted(collections.Counter(c for l in openfile for c in l).items())

f = open(sys.argv[1])
print(filecharcount(f))

As a fold

Character counting can be conveniently expressed in terms of fold/reduce. See the example below, which also generates column-wrapped output:

Works with: Python version 3
'''Character counting as a fold'''

from functools import reduce
from itertools import repeat
from os.path import expanduser


# charCounts :: String -> Dict Char Int
def charCounts(s):
    '''A dictionary of
       (character, frequency) mappings
    '''
    def tally(dct, c):
        dct[c] = 1 + dct[c] if c in dct else 1
        return dct
    return reduce(tally, list(s), {})


# TEST ----------------------------------------------------
# main :: IO ()
def main():
    '''Listing in descending order of frequency.'''

    print(
        tabulated(
            'Descending order of frequency:\n'
        )(compose(repr)(fst))(compose(str)(snd))(
            5
        )(stet)(
            sorted(
                charCounts(
                    readFile('~/Code/charCount/readme.txt')
                ).items(),
                key=swap,
                reverse=True
            )
        )
    )


# GENERIC -------------------------------------------------

# chunksOf :: Int -> [a] -> [[a]]
def chunksOf(n):
    '''A series of lists of length n,
       subdividing the contents of xs.
       Where the length of xs is not evenly divible,
       the final list will be shorter than n.'''
    return lambda xs: reduce(
        lambda a, i: a + [xs[i:n + i]],
        range(0, len(xs), n), []
    ) if 0 < n else []


# compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
def compose(g):
    '''Right to left function composition.'''
    return lambda f: lambda x: g(f(x))


# fst :: (a, b) -> a
def fst(tpl):
    '''First member of a pair.'''
    return tpl[0]


# readFile :: FilePath -> IO String
def readFile(fp):
    '''The contents of any file at the path
       derived by expanding any ~ in fp.'''
    with open(expanduser(fp), 'r', encoding='utf-8') as f:
        return f.read()


# paddedMatrix :: a -> [[a]] -> [[a]]
def paddedMatrix(v):
    ''''A list of rows padded to equal length
        (where needed) with instances of the value v.'''
    def go(rows):
        return paddedRows(
            len(max(rows, key=len))
        )(v)(rows)
    return lambda rows: go(rows) if rows else []


# paddedRows :: Int -> a -> [[a]] -[[a]]
def paddedRows(n):
    '''A list of rows padded (but never truncated)
       to length n with copies of value v.'''
    def go(v, xs):
        def pad(x):
            d = n - len(x)
            return (x + list(repeat(v, d))) if 0 < d else x
        return list(map(pad, xs))
    return lambda v: lambda xs: go(v, xs) if xs else []


# showColumns :: Int -> [String] -> String
def showColumns(n):
    '''A column-wrapped string
       derived from a list of rows.'''
    def go(xs):
        def fit(col):
            w = len(max(col, key=len))

            def pad(x):
                return x.ljust(4 + w, ' ')
            return ''.join(map(pad, col)).rstrip()

        q, r = divmod(len(xs), n)
        return '\n'.join(map(
            fit,
            zip(*paddedMatrix('')(
                chunksOf(q + int(bool(r)))(xs)
            ))
        ))
    return lambda xs: go(xs)


# snd :: (a, b) -> b
def snd(tpl):
    '''Second member of a pair.'''
    return tpl[1]


# stet :: a -> a
def stet(x):
    '''The identity function.
       The usual 'id' is reserved in Python.'''
    return x


# swap :: (a, b) -> (b, a)
def swap(tpl):
    '''The swapped components of a pair.'''
    return (tpl[1], tpl[0])


# tabulated :: String -> (a -> String) ->
#                        (b -> String) ->
#                        Int ->
#                        (a -> b) -> [a] -> String
def tabulated(s):
    '''Heading -> x display function -> fx display function ->
          number of columns -> f -> value list -> tabular string.'''
    def go(xShow, fxShow, intCols, f, xs):
        def mxw(fshow, g):
            return max(map(compose(len)(fshow), map(g, xs)))
        w = mxw(xShow, lambda x: x)
        fw = mxw(fxShow, f)
        return s + '\n' + showColumns(intCols)([
            xShow(x).rjust(w, ' ') + ' -> ' + (
                fxShow(f(x)).rjust(fw, ' ')
            )
            for x in xs
        ])
    return lambda xShow: lambda fxShow: lambda nCols: (
        lambda f: lambda xs: go(
            xShow, fxShow, nCols, f, xs
        )
    )


# MAIN ---
if __name__ == '__main__':
    main()
Output:
Descending order of frequency:

 ' ' -> 568     ')' ->  62     'v' ->  25     'w' ->   7     '5' ->   3
'\t' -> 382     '(' ->  62     '1' ->  24     'k' ->   7     '4' ->   3
 'e' -> 274     'd' ->  60     'G' ->  22     '9' ->   6     '+' ->   3
 'n' -> 233     'g' ->  59     ']' ->  17     'S' ->   5     '¬' ->   2
'\n' -> 228     'u' ->  58     '[' ->  17     'R' ->   5     '=' ->   2
 't' -> 204     '|' ->  54     'λ' ->  16     'M' ->   5     '.' ->   2
 's' -> 198     'x' ->  53     '2' ->  15     'F' ->   5     'L' ->   1
 '-' -> 178     'm' ->  52     'N' ->  11     '<' ->   5     'C' ->   1
 'i' -> 145     'c' ->  52     '}' ->  10     '6' ->   5     'A' ->   1
 'o' -> 126     'h' ->  47     '{' ->  10     'z' ->   4     '3' ->   1
 'f' -> 100     ':' ->  47     'T' ->  10     "'" ->   4     '&' ->   1
 'r' ->  96     ',' ->  38     'I' ->  10     '^' ->   3     '$' ->   1
 'a' ->  86     'b' ->  32     '0' ->  10     'E' ->   3
 'l' ->  70     'y' ->  31     '"' ->  10     '8' ->   3
 'p' ->  68     '>' ->  28     'J' ->   9     '7' ->   3

Procedural

Without using collections.Counter

import string
if hasattr(string, 'ascii_lowercase'):
    letters = string.ascii_lowercase       # Python 2.2 and later
else:
    letters = string.lowercase             # Earlier versions
offset = ord('a')

def countletters(file_handle):
    """Traverse a file and compute the number of occurences of each letter
    return results as a simple 26 element list of integers."""
    results = [0] * len(letters)
    for line in file_handle:
        for char in line:
            char = char.lower()
            if char in letters:
                results[ord(char) - offset] += 1
                # Ordinal minus ordinal of 'a' of any lowercase ASCII letter -> 0..25
    return results

if __name__ == "__main__":
    sourcedata = open(sys.argv[1])
    lettercounts = countletters(sourcedata)
    for i in xrange(len(lettercounts)):
        print "%s=%d" % (chr(i + ord('a')), lettercounts[i]),

This example defines the function and provides a sample usage. The if ... __main__... line allows it to be cleanly imported into any other Python code while also allowing it to function as a standalone script. (A very common Python idiom).

Using a numerically indexed array (list) for this is artificial and clutters the code somewhat.

Using defaultdict

Works with: Python version 2.5+ and 3.x
...
from collections import defaultdict
def countletters(file_handle):
    """Count occurences of letters and return a dictionary of them
    """
    results = defaultdict(int)
    for line in file_handle:
        for char in line:
            if char.lower() in letters:
                c = char.lower()
                results[c] += 1
    return results

Which eliminates the ungainly fiddling with ordinal values and offsets in function countletters of a previous example above. More importantly it allows the results to be more simply printed using:

lettercounts = countletters(sourcedata)
for letter,count in lettercounts.iteritems():
    print "%s=%s" % (letter, count),

Again eliminating all fussing with the details of converting letters into list indices.

Quackery

  [ [] 26 times [ 0 join ] ]  is makecountnest (     --> [ )

  [ char A char Z 1+ within ] is ischar        (   c --> b )

  [ char A -
    2dup peek 1+ unrot poke ] is tallychar     ( [ c --> [ )

  [ makecountnest swap
    witheach
      [ upper dup ischar iff
          tallychar
        else drop ] ]         is countchars    (   $ --> [ )

  [ say "Letter count:" cr
    witheach
      [ say "  "
        i^ char A + emit
            say ":" echo
            cr ] ]            is echocount     (   [ -->   )

   [ sharefile 0 = if
       [ $ " not found."
         join fail ]
     countchars
     echocount ]              is fileletters  (    $ -->   )

Testing in Quackery shell:

O> $ "quackery.py" fileletters ( i.e. the Quackery source file )
...
Letter count:
  A:1324
  B:433
  C:819
  D:897
  E:2336
  F:647
  G:237
  H:402
  I:1393
  J:82
  K:359
  L:683
  M:537
  N:1330
  O:1171
  P:835
  Q:93
  R:1393
  S:1547
  T:1769
  U:697
  V:105
  W:257
  X:281
  Y:145
  Z:34

Stack empty.

/O> $ "nosuchfile.txt" fileletters
...

       Problem: nosuchfile.txt not found.
Quackery Stack:
  Return stack: {[...] 0} {quackery 1} {[...] 11} {shell 5} {quackery 1} {[...] 1} {fileletters 4}



Quick Basic/QBASIC/PDS 7.1/VB-DOS

This version counts valid letters from A to Z (including Ñ in Spanish alphabet) or characters in a file. Takes in account accented vowels. It runs in QB, QBASIC, PDS 7.1 and VB_DOS as is.

' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
'  Program CountCar                                   '
'                                                     '
'  This program counts how many distinct characters   '
'  have a text file specified by the user.            '
' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '
' OPTION EXPLICIT  ' Remove comment in VB-DOS

' Register
TYPE regChar
  Character AS STRING * 3
  Count AS LONG
END TYPE

' Var
DIM iChar AS INTEGER
DIM iCL AS INTEGER
DIM iCountChars AS INTEGER
DIM iFile AS INTEGER
DIM i AS INTEGER
DIM lMUC AS LONG
DIM iMUI AS INTEGER
DIM lLUC AS LONG
DIM iLUI AS INTEGER
DIM iMaxIdx AS INTEGER
DIM iP AS INTEGER
DIM iPause AS INTEGER
DIM iPMI AS INTEGER
DIM iPrint AS INTEGER
DIM lHowMany AS LONG
DIM lTotChars AS LONG
DIM sTime AS SINGLE
DIM strFile AS STRING
DIM strTxt AS STRING
DIM strDate AS STRING
DIM strTime AS STRING
DIM strKey AS STRING
CONST LngReg = 256
CONST Letters = 1
CONST FALSE = 0
CONST TRUE = NOT FALSE

'------Main program cycle

' Initialize variables
strDate = DATE$
strTime = TIME$
iFile = FREEFILE


DO
  CLS
  PRINT "This program counts letters or characters in a text file."
  PRINT
  INPUT "File to open: ", strFile
  OPEN strFile FOR BINARY AS #iFile
  IF LOF(iFile) > 0 THEN
    PRINT "Count: 1) Letters 2) Characters (1 or 2)";
    DO
      strKey = INKEY$
    LOOP UNTIL strKey = "1" OR strKey = "2"
    PRINT ". Option selected: "; strKey
    iCL = VAL(strKey)
    sTime = TIMER
    iP = POS(0)
    lHowMany = LOF(iFile)
    strTxt = SPACE$(LngReg)

    IF iCL = Letters THEN
      iMaxIdx = 26
    ELSE
      iMaxIdx = 255
    END IF

    IF iMaxIdx <> iPMI THEN
      iPMI = iMaxIdx
      REDIM rChar(0 TO iMaxIdx) AS regChar

      FOR i = 0 TO iMaxIdx
        IF iCL = Letters THEN
          strTxt = CHR$(i + 65)
          IF i = 26 THEN strTxt = CHR$(165)
        ELSE
          SELECT CASE i
            CASE 0: strTxt = "nul"
            CASE 7: strTxt = "bel"
            CASE 9: strTxt = "tab"
            CASE 10: strTxt = "lf"
            CASE 11: strTxt = "vt"
            CASE 12: strTxt = "ff"
            CASE 13: strTxt = "cr"
            CASE 28: strTxt = "fs"
            CASE 29: strTxt = "gs"
            CASE 30: strTxt = "rs"
            CASE 31: strTxt = "us"
            CASE 32: strTxt = "sp"
            CASE ELSE: strTxt = CHR$(i)
          END SELECT
        END IF
        rChar(i).Character = strTxt
      NEXT i
    ELSE
      FOR i = 0 TO iMaxIdx
        rChar(i).Count = 0
      NEXT i
    END IF

    PRINT "Looking for ";
    IF iCL = Letters THEN PRINT "letters.";  ELSE PRINT "characters.";
    PRINT " File is"; STR$(lHowMany); " in size. Working"; : COLOR 23: PRINT "..."; : COLOR (7)
    DO WHILE LOC(iFile) < LOF(iFile)
      IF LOC(iFile) + LngReg > LOF(iFile) THEN
        strTxt = SPACE$(LOF(iFile) - LOC(iFile))
      END IF
      GET #iFile, , strTxt
      FOR i = 1 TO LEN(strTxt)
        IF iCL = Letters THEN
          iChar = ASC(UCASE$(MID$(strTxt, i, 1)))
          SELECT CASE iChar
            CASE 164: iChar = 165
            CASE 160: iChar = 65
            CASE 130, 144: iChar = 69
            CASE 161: iChar = 73
            CASE 162: iChar = 79
            CASE 163, 129: iChar = 85
          END SELECT
          iChar = iChar - 65
          
          ' Validates if iChar is a letter
          IF iChar >= 0 AND iChar <= 25 THEN
            rChar(iChar).Count = rChar(iChar).Count + 1
          ELSEIF iChar = 100 THEN ' CHR$(165)
            rChar(iMaxIdx).Count = rChar(iMaxIdx).Count + 1
          END IF
        ELSE
          iChar = ASC(MID$(strTxt, i, 1))
          rChar(iChar).Count = rChar(iChar).Count + 1
        END IF
      NEXT i
    LOOP
    CLOSE #iFile

    ' Show the characters found
    lMUC = 0
    iMUI = 0
    lLUC = 2147483647
    iLUI = 0
    iPrint = FALSE
    lTotChars = 0
    iCountChars = 0
    iPause = FALSE
    CLS
    IF iCL = Letters THEN PRINT "Letters found: ";  ELSE PRINT "Characters found: ";
    FOR i = 0 TO iMaxIdx
      ' Most Used Character
      IF lMUC < rChar(i).Count THEN
        lMUC = rChar(i).Count
        iMUI = i
      END IF

      ' Print character
      IF rChar(i).Count > 0 THEN
        strTxt = ""
        IF iPrint THEN strTxt = ", " ELSE iPrint = TRUE
        strTxt = strTxt + LTRIM$(RTRIM$(rChar(i).Character))
        strTxt = strTxt + "=" + LTRIM$(STR$(rChar(i).Count))
        iP = POS(0)
        IF iP + LEN(strTxt) + 1 >= 80 AND iPrint THEN
          PRINT ","
          IF CSRLIN >= 23 AND NOT iPause THEN
            iPause = TRUE
            PRINT "Press a key to continue..."
            DO
              strKey = INKEY$
            LOOP UNTIL strKey <> ""
          END IF
          strTxt = MID$(strTxt, 3)
        END IF
        PRINT strTxt;
        lTotChars = lTotChars + rChar(i).Count
        iCountChars = iCountChars + 1

        ' Least Used Character
        IF lLUC > rChar(i).Count THEN
          lLUC = rChar(i).Count
          iLUI = i
        END IF
      END IF
    NEXT i

    PRINT "."

    ' Shows the summary
    PRINT
    PRINT "File analyzed....................: "; strFile
    PRINT "Looked for.......................: "; : IF iCL = Letters THEN PRINT "Letters" ELSE PRINT "Characters"
    PRINT "Total characters in file.........:"; lHowMany
    PRINT "Total characters counted.........:"; lTotChars
    IF iCL = Letters THEN PRINT "Characters discarded on count....:"; lHowMany - lTotChars
    PRINT "Distinct characters found in file:"; iCountChars; "of"; iMaxIdx + 1
    PRINT "Most used character was..........: ";
      iPrint = FALSE
      FOR i = 0 TO iMaxIdx
        IF rChar(i).Count = lMUC THEN
          IF iPrint THEN PRINT ", ";  ELSE iPrint = TRUE
          PRINT RTRIM$(LTRIM$(rChar(i).Character));
        END IF
      NEXT i
    PRINT " ("; LTRIM$(STR$(rChar(iMUI).Count)); " times)"
    PRINT "Least used character was.........: ";
      iPrint = FALSE
      FOR i = 0 TO iMaxIdx
        IF rChar(i).Count = lLUC THEN
          IF iPrint THEN PRINT ", ";  ELSE iPrint = TRUE
          PRINT RTRIM$(LTRIM$(rChar(i).Character));
        END IF
      NEXT i
      PRINT " ("; LTRIM$(STR$(rChar(iLUI).Count)); " times)"
    PRINT "Time spent in the process........:"; TIMER - sTime; "seconds"
  ELSE
    ' File does not exist
    CLOSE #iFile
    KILL strFile
    PRINT
    PRINT "File does not exist."
  END IF

  ' Again?
  PRINT
  PRINT "Again? (Y/n)"
  DO
    strTxt = UCASE$(INKEY$)
  LOOP UNTIL strTxt = "N" OR strTxt = "Y" OR strTxt = CHR$(13) OR strTxt = CHR$(27)
LOOP UNTIL strTxt = "N" OR strTxt = CHR$(27)

CLS
PRINT "End of execution."
PRINT "Start time: "; strDate; " "; strTime; ", end time: "; DATE$; " "; TIME$; "."
END
' ---End of main program cycle

Output:

This program counts letters or characters in a text file.

File to open: readme.txt
Count: 1) Letters 2) Characters (1 or 2). Option selected: 1
Looking for letters. File is 23769 in size. Working...

Letters found: A=1427, B=306, C=583, D=530, E=2098, F=279, G=183, H=501,
I=1177, J=15, K=34, L=741, M=379, N=1219, O=1183, P=312, Q=32, R=1105, S=1079,
T=1309, U=660, V=346, W=147, X=190, Y=242, Z=70, Ñ=5.

File analyzed....................: readme.txt
Looked for.......................: Letters
Total characters in file.........: 23769
Total characters counted.........: 16152
Characters discarded on count....: 7617
Distinct characters found in file: 27 of 27
Most used character was..........: E (2098 times)
Least used character was.........: Ñ (5 times)
Time spent in the process........: .3789063 seconds

Again? (Y/n)

R

Using summary

letter.frequency <- function(filename)
{
    file <- paste(readLines(filename), collapse = '')
    chars <- strsplit(file, NULL)[[1]]
    summary(factor(chars))
}

Usage on itself:

> source('letter.frequency.r')
> letter.frequency('letter.frequency.r')
    -  ,  .  '  (  )  [  ]  {  }  <  =  1  a  c  d  e  f  h  i  l  L  m  n  N  o  p  q  r  s  t  u  U  y 
22  3  2  1  2  6  6  2  2  1  1  3  1  1  9  6  1 14  7  2  7  8  3  4  6  1  3  3  1  8  8  7  3  1  2

Using table

R's table function is more idiomatic. For variety, we will use read.delim rather than readLines and show how to only count letters. It is worth noting that readLines is prone to counting empty lines. This may be undesirable.

letterFreq <- function(filename, lettersOnly)
{
  txt <- read.delim(filename, header = FALSE, stringsAsFactors = FALSE, allowEscapes = FALSE, quote = "")
  count <- table(strsplit(paste0(txt[,], collapse = ""), ""))
  if(lettersOnly) count[names(count) %in% c(LETTERS, letters)] else count
}
Output:

For fun, we'll use this page for input. However, HTML rarely parses well and the variety of text here is so large that I suspect inaccurate output.

> print(letterFreq('https://rosettacode.org/wiki/Letter_frequency', TRUE))

    a     A     b     B     c     C     d     D     e     E     f     F     g     G     h     H     i     I 
38186   666  8008   350 16585  1263  4151   277 15020   713  3172   529  3079   149  4549   161  9397   690 
    j     J     k     K     l     L     m     M     n     N     o     O     p     P     q     Q     r     R 
  311   113  3294    76 15906   928  3333   322 26795   355  8926   456 22702   497  1877    39 15055   591 
    s     S     t     T     u     U     v     V     w     W     x     X     y     Y     z     Z 
46527   695 15549   597  5268   269  1003   128  4134   148  1239   144  3037    55   127    77 

Racket

#lang racket
(require math)

(define (letter-frequencies ip)
  (count-samples
   (port->list read-char ip)))

(letter-frequencies (open-input-string "abaabdc"))
Output:
'(#\a #\b #\d #\c)
'(3 2 1 1)

Using input from a text file:

(letter-frequencies (open-input-file "somefile.txt"))

Raku

(formerly Perl 6)

In Raku, whenever you want to count things in a collection, the rule of thumb is to use the Bag structure.

In response to some of the breathless exposition in the Frink entry.

  • Has a Unicode-aware function, which intelligently enumerates through what a human would consider to be a single visible character. - Raku doesn't have a special Unicode aware string processing function, rather all of Rakus text/string wrangling functions are Unicode aware by default.
  • Unicode-aware lowercase function. - See above: lowercase, uppercase, fold-case, title-case, all Unicode aware by default.
  • Uses full Unicode tables to determine what is a "letter." - Um... Yeah, Unicode aware by default.
  • Works with high Unicode characters, that is above \uFFFF. - OK, now we're just repeating ourselves.
  • Normalize Unicode characters with its normalizeUnicode function. - Raku; normalized by default.
  • Implements all of (NFC, NFD, NFKC, NFKD). NFC is the default. - Yep.

"How many other languages in this page do all or any of this correctly?" Quite a few I suspect. Some even moreso than Frink.

.&ws.say for slurp.comb.Bag.sort: -*.value;

sub ws ($pair) { 
    $pair.key ~~ /\n/
    ?? ('NEW LINE' => $pair.value)
    !! $pair.key ~~ /\s/
    ?? ($pair.key.uniname => $pair.value)
    !! $pair
}
Output when fed the same Les Misérables text file as used in the Word frequency task:
SPACE => 522095
e => 325692
t => 222916
a => 199790
o => 180974
h => 170210
n => 167006
i => 165201
s => 157585
r => 145118
d => 106987
l => 97131
NEW LINE => 67662
u => 67340
c => 62717
m => 56021
f => 53494
w => 53301
, => 48784
g => 46060
p => 39932
y => 37985
b => 34276
. => 30589
v => 24045
" => 14340
k => 14169
T => 12547
- => 11037
I => 10067
A => 7355
H => 6600
M => 6206
; => 5885
E => 4968
C => 4583
S => 4392
' => 3938
x => 3692
! => 3539
R => 3531
P => 3424
O => 3401
j => 3390
B => 3185
W => 3180
N => 3053
? => 2976
F => 2754
G => 2508
: => 2468
J => 2448
L => 2444
q => 2398
V => 2200
_ => 2070
z => 1847
D => 1756
é => 1326
Y => 1238
U => 895
1 => 716
8 => 412
X => 333
K => 321
è => 292
3 => 259
2 => 248
5 => 220
0 => 218
* => 181
4 => 181
) => 173
( => 173
6 => 167
É => 146
7 => 143
Q => 135
] => 122
[ => 122
9 => 117
æ => 106
= => 75
ê => 74
Z => 59
à => 59
â => 56
> => 50
< => 50
/ => 50
ç => 48
NO-BREAK SPACE => 45
î => 39
ü => 37
| => 36
ô => 34
# => 26
ù => 18
ï => 18
Æ => 10
û => 9
+ => 5
È => 5
ë => 5
À => 4
@ => 2
ñ => 2
Ç => 2
$ => 2
% => 1
& => 1
{ => 1
} => 1
½ => 1

Raven

define count_letters use $words
   { } as $wordHash    [ ] as $keys   [ ]  as $vals
   $words each chr
      dup $wordHash swap get 0 prefer 1 +   # stack: chr cnt
      swap $wordHash swap set
   $wordHash keys copy sort each
      dup $keys push
      $wordHash swap get $vals push
   $keys $vals combine  print "\n" print

"test.dat" as $file
$file read as $all_data
$all_data count_letters

Refal

$ENTRY Go {
    , <Arg 1>: {
        = <Prout 'No filename given'>;
        e.File, <ReadFile 1 e.File>: e.Text,
                <Tally e.Text>: e.Counts
                = <ShowLetterCounts (e.Counts) <Letters>>;
    };
};

Letters {
    = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
};

ShowLetterCounts {
    (e.T) = ;
    (e.T) s.L e.Ls,
        <Upper s.L>: s.UL, <Item (e.T) s.UL>: s.ULN,
        <Lower s.L>: s.LL, <Item (e.T) s.LL>: s.LLN,
        <+ s.ULN s.LLN>: s.Total
        = <Prout s.UL s.LL ': ' <Symb s.Total>>
          <ShowLetterCounts (e.T) e.Ls>;
};

ReadFile {
    s.Chan e.Filename =
        <Open 'r' s.Chan e.Filename>
        <ReadFile (s.Chan)>;
    (s.Chan), <Get s.Chan>: {
        0 = <Close s.Chan>;
        e.Line = e.Line '\n' <ReadFile (s.Chan)>;
    };
};

Tally {
    (e.T) = e.T;
    (e.T) s.X e.Xs = <Tally (<Inc (e.T) s.X>) e.Xs>;
    e.Xs = <Tally () e.Xs>;
}

Inc {
    (e.1 (s.I s.N) e.2) s.I = e.1 (s.I <+ 1 s.N>) e.2;
    (e.X) s.I = e.X (s.I 1);
};

Item {
    (e.1 (s.I s.N) e.2) s.I = s.N;
    (e.X) s.I = 0;
};
Output:

The result of running the program on its own source file:

Aa: 22
Bb: 2
Cc: 16
Dd: 5
Ee: 75
Ff: 10
Gg: 5
Hh: 11
Ii: 26
Jj: 1
Kk: 1
Ll: 49
Mm: 8
Nn: 33
Oo: 18
Pp: 6
Qq: 1
Rr: 17
Ss: 55
Tt: 44
Uu: 14
Vv: 2
Ww: 5
Xx: 12
Yy: 7
Zz: 1

REXX

version 1

It should be noted that the file being read is read one line at time, so the line-end characters (presumably the
line-feed, carriage return, new-line, or whatever control characters are being used) are not reported.

These characters could be read and reported if the   charin   BIF would be used instead of the   linein   BIF.

Also note that this REXX program is ASCII or EBCDIC independent, but what constitutes a letter is restricted to
the Latin (Roman) alphabet (that is, which characters are considered to be letters of a particular language.

The version of REXX that was used was the English version of Regina REXX.   It should be noted that almost all
REXX interpreters assume the English language for such things as determining what characters are considered
letters unless another language is specified   (Regina REXX uses an environmental variable for this purpose).

All characters are still counted, whether a letter or not, including non-displayable characters.

/*REXX program counts the occurrences of all characters in a file,  and note that all   */
/* Latin alphabet letters are uppercased for also counting {Latin} letters (both cases).*/
/*════════════════════════════════════~~~~~~~~~~════════════════════════════════════════*/
abc = 'abcdefghijklmnopqrstuvwxyz'               /*define an (Latin or English) alphabet*/
abcU= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'               /*define an uppercase version of  [↑]. */
parse arg fileID .                               /*this last char isn't a middle dot: · */
if fileID==''  then fileID= 'JUNK.TXT'           /*¿none specified? Then use the default*/
totChars= 0;           totLetters= 0             /*count of all chars and of all letters*/
pad= left('',18);      pad9= left('', 18%2)      /*used for the indentations of output. */
@.= 0                                            /*wouldn't it be neat to use Θ instead?*/
     do j=1  while lines(fileID)\==0             /*read the file 'til the cows come home*/
     rec= linein(fileID)                         /*get a line/record from the input file*/
                                                 /* [↓]  process all characters in  REC.*/
       do k=1  for length(rec)                   /*examine/count each of the characters.*/
       totChars= totChars + 1                    /*bump count of number of characters.  */
       c= substr(rec, k, 1);      @.c= @.c + 1   /*Peel off a character; bump its count.*/
       if \datatype(c, 'M')  then iterate        /*Not a Latin letter?   Get next char.⌠*/
       totLetters= totLetters + 1                /*bump the count for [Latin] letters. ⌡*/
       upper c                                   /* ◄─────◄ uppercase a Latin character.*/
       @..c= @..c + 1                            /*bump the  (Latin)  letter's count.   */
       end   /*k*/                               /*no Greek glyphs:  αßΓπΣσµτΦΘΩδφε ··· */
     end     /*j*/                               /*maybe we're ½ done by now, or mäÿbé ¬*/
                          LL= '(Latin) letter'   /*literal used for a  "SAY"  (below).  */
w= length(totChars)                              /*used for right─aligning the counts.  */
say 'file ─────'  fileId  "───── has"   j-1   'records and has'   totLetters LL"s.";   say
     do L=0  for 256;    c= d2c(L)               /*display all none─zero letter counts. */
     if @..c==0  then iterate                    /*Has a zero count? Then skip character*/
     say pad9  LL' '    c    " (also" translate(c,abc,abcU)')  count:'      right(@..c, w)
     end   /*L*/                                 /*we may be in a rut, but not a cañyon.*/
say                                              /*¡The old name for Eygpt was Æygpt!  _*/
say 'file ─────'    fileId     "───── has"     totChars     'characters.'          /* √ */
say                                              /*The name for « » chars is guillemets.*/
     do #=0  for 256;    y= d2c(#)               /*display all none─zero char counts.   */
     if @.y==0  then iterate                     /*¿Å zero count?  Then ignore character*/
     c= d2c(#);               ch= c              /*C  is the character glyph of a char. */
     if c<<' ' | #==255  then ch=                /*don't show some control characters.  */
     if c==' '           then ch= 'blank'        /*show a blank's  {true}  name.        */
     say pad right(ch, 5)         " ('"d2x(#,2)"'x  character count:"      right(@.c, w)
     end   /*#*/                                 /*255 isn't quite ∞, but sometimes ∙∙∙ */
say                                              /*not a good place for dithering: ░▒▓█ */
say  pad   pad9   '☼ end─of─list ☼'              /*show we are at the end of the list.  */
/*§§§§ Talk about a mishmash of 2¢ comments. ▬▬^▬▬ stick a fork in it, we're all done. ☻*/

output   when using the (above) REXX program for the input file:

Note that this REXX program works with ASCII or EBCDIC, but the order of the output will
be different because of the order in which EBCDIC and ASCII stores characters.

file ───── JUNK.TXT ───── has 42 records and has 1652 (Latin) letters.

          (Latin) letter  A  (also a)  count:  146
          (Latin) letter  B  (also b)  count:   26
          (Latin) letter  C  (also c)  count:  104
          (Latin) letter  D  (also d)  count:   58
          (Latin) letter  E  (also e)  count:  187
          (Latin) letter  F  (also f)  count:   53
          (Latin) letter  G  (also g)  count:   25
          (Latin) letter  H  (also h)  count:   80
          (Latin) letter  I  (also i)  count:   89
          (Latin) letter  J  (also j)  count:    6
          (Latin) letter  K  (also k)  count:   13
          (Latin) letter  L  (also l)  count:   97
          (Latin) letter  M  (also m)  count:   28
          (Latin) letter  N  (also n)  count:  102
          (Latin) letter  O  (also o)  count:  106
          (Latin) letter  P  (also p)  count:   38
          (Latin) letter  Q  (also q)  count:    3
          (Latin) letter  R  (also r)  count:  111
          (Latin) letter  S  (also s)  count:   96
          (Latin) letter  T  (also t)  count:  175
          (Latin) letter  U  (also u)  count:   48
          (Latin) letter  V  (also v)  count:    3
          (Latin) letter  W  (also w)  count:   18
          (Latin) letter  X  (also x)  count:    9
          (Latin) letter  Y  (also y)  count:   25
          (Latin) letter  Z  (also z)  count:    6

file ───── JUNK.TXT ───── has 3778 characters.

                          ('02'x  character count:    1
                          ('0F'x  character count:    2
                          ('11'x  character count:    2
                          ('15'x  character count:    4
                          ('16'x  character count:    4
                          ('18'x  character count:    1
                          ('19'x  character count:    1
                   blank  ('20'x  character count: 1477
                       !  ('21'x  character count:    1
                       "  ('22'x  character count:   14
                       #  ('23'x  character count:    6
                       %  ('25'x  character count:    1
                       '  ('27'x  character count:   47
                       (  ('28'x  character count:   23
                       )  ('29'x  character count:   22
                       *  ('2A'x  character count:   86
                       +  ('2B'x  character count:    4
                       ,  ('2C'x  character count:   16
                       -  ('2D'x  character count:    1
                       .  ('2E'x  character count:   40
                       /  ('2F'x  character count:   88
                       0  ('30'x  character count:    8
                       1  ('31'x  character count:   10
                       2  ('32'x  character count:   11
                       5  ('35'x  character count:    7
                       6  ('36'x  character count:    2
                       8  ('38'x  character count:    2
                       9  ('39'x  character count:    3
                       :  ('3A'x  character count:    5
                       ;  ('3B'x  character count:    8
                       <  ('3C'x  character count:    2
                       =  ('3D'x  character count:   38
                       ?  ('3F'x  character count:    5
                       @  ('40'x  character count:    9
                       A  ('41'x  character count:    2
                       B  ('42'x  character count:    1
                       C  ('43'x  character count:    8
                       D  ('44'x  character count:    6
                       E  ('45'x  character count:    5
                       F  ('46'x  character count:    1
                       G  ('47'x  character count:    3
                       H  ('48'x  character count:    2
                       I  ('49'x  character count:    8
                       J  ('4A'x  character count:    2
                       K  ('4B'x  character count:    2
                       L  ('4C'x  character count:   22
                       M  ('4D'x  character count:    2
                       N  ('4E'x  character count:    3
                       O  ('4F'x  character count:    1
                       P  ('50'x  character count:    2
                       Q  ('51'x  character count:    1
                       R  ('52'x  character count:    3
                       S  ('53'x  character count:    2
                       T  ('54'x  character count:    9
                       U  ('55'x  character count:    4
                       V  ('56'x  character count:    1
                       W  ('57'x  character count:    1
                       X  ('58'x  character count:    4
                       Y  ('59'x  character count:    2
                       Z  ('5A'x  character count:    1
                       [  ('5B'x  character count:    3
                       \  ('5C'x  character count:    2
                       ]  ('5D'x  character count:    3
                       ^  ('5E'x  character count:    1
                       _  ('5F'x  character count:    1
                       a  ('61'x  character count:  144
                       b  ('62'x  character count:   25
                       c  ('63'x  character count:   96
                       d  ('64'x  character count:   52
                       e  ('65'x  character count:  182
                       f  ('66'x  character count:   52
                       g  ('67'x  character count:   22
                       h  ('68'x  character count:   78
                       i  ('69'x  character count:   81
                       j  ('6A'x  character count:    4
                       k  ('6B'x  character count:   11
                       l  ('6C'x  character count:   75
                       m  ('6D'x  character count:   26
                       n  ('6E'x  character count:   99
                       o  ('6F'x  character count:  105
                       p  ('70'x  character count:   36
                       q  ('71'x  character count:    2
                       r  ('72'x  character count:  108
                       s  ('73'x  character count:   94
                       t  ('74'x  character count:  166
                       u  ('75'x  character count:   44
                       v  ('76'x  character count:    2
                       w  ('77'x  character count:   17
                       x  ('78'x  character count:    5
                       y  ('79'x  character count:   23
                       z  ('7A'x  character count:    5
                       {  ('7B'x  character count:    2
                       |  ('7C'x  character count:    1
                       }  ('7D'x  character count:    2
                       ~  ('7E'x  character count:   10
                       é  ('82'x  character count:    1
                       ä  ('84'x  character count:    1
                       Å  ('8F'x  character count:    1
                       Æ  ('92'x  character count:    1
                       ÿ  ('98'x  character count:    1
                       ¢  ('9B'x  character count:    1
                       ñ  ('A4'x  character count:    1
                       ¿  ('A8'x  character count:    2
                       ¬  ('AA'x  character count:    1
                       ½  ('AB'x  character count:    1
                       ¡  ('AD'x  character count:    1
                       «  ('AE'x  character count:    1
                       »  ('AF'x  character count:    1
                       ░  ('B0'x  character count:    1
                       ▒  ('B1'x  character count:    1
                       ▓  ('B2'x  character count:    1
                       ─  ('C4'x  character count:   30
                       ═  ('CD'x  character count:   76
                       █  ('DB'x  character count:    1
                       α  ('E0'x  character count:    1
                       ß  ('E1'x  character count:    1
                       Γ  ('E2'x  character count:    1
                       π  ('E3'x  character count:    1
                       Σ  ('E4'x  character count:    1
                       σ  ('E5'x  character count:    1
                       µ  ('E6'x  character count:    1
                       τ  ('E7'x  character count:    1
                       Φ  ('E8'x  character count:    1
                       Θ  ('E9'x  character count:    2
                       Ω  ('EA'x  character count:    1
                       δ  ('EB'x  character count:    1
                       ∞  ('EC'x  character count:    1
                       φ  ('ED'x  character count:    1
                       ε  ('EE'x  character count:    1
                       ⌠  ('F4'x  character count:    1
                       ⌡  ('F5'x  character count:    1
                       ∙  ('F9'x  character count:    3
                       ·  ('FA'x  character count:    4
                       √  ('FB'x  character count:    1

                             ☼ end─of─list ☼

Version 2 (for TSO)

/*REXX program counts the occurences of all characters in a file
* Adapted version 1 for TSO (EXECIO instead of linein)
* No translation to uppercase takes place
* There is no need for tails being hex
* 25.07.2012 Walter Pachl
***********************************************************************/

  Parse arg dsn .                    /*Data set to be processed       */
  if dsn='' Then                     /*none specified?                */
    dsn='PRIV.V100(TEST)'            /* Use default.                  */
  c.=0                               /* Character counts              */
  "ALLOC   FI(IN) DA("dsn") SHR REUSE"
  'EXECIO   * DISKR IN (STEM L. FINIS'
  'FREE   FI(IN)'
  totChars=0                         /*count of the total num of chars*/
  totLetters=0                       /*count of the total num letters.*/
  indent=left('',20)                 /*used for indentation of output.*/

  do j=1 to l.0                      /*process all lines              */
    rec=l.j                          /*take line number j             */
    Say '>'rec'<' length(rec)        /*that's in PRIV.V100(TEST)      */
    Say ' E8C44D8FF015674BCDEF'
    Say ' 61100711200000000002'
    do k=1 for length(rec)           /*loop over characters           */
      totChars=totChars+1            /*Increment total number of chars*/
      c=substr(rec,k,1)              /*get character number k         */
      c.c=c.c+1                      /*increment the character's count*/
      End
    End                              /*maybe we're ½ done by now, or ¬*/

  w=length(totChars)                 /*used for right-aligning counts.*/
  say 'file -----' dsn "----- has" j-1 'records.'
  say 'file -----' dsn "----- has" totChars 'characters.'

  do L=0 to 255                      /* display nonzero letter counts */
    c=d2c(l)                         /* the character in question     */
    if c.c>0 &,                      /* was found in the file         */
       datatype(c,'M')>0 Then Do     /* and is a Latin letter         */
      say indent "(Latin) letter " c 'count:' right(c.c,w) /* tell    */
      totLetters=totLetters+c.c      /* increment number of letters   */
      End
    End

  say 'file -----' dsn "----- has" totLetters '(Latin) letters.'
  say '                           other characters follow'
  other=0
  do m=0 to 255                      /* now for non-letters           */
    c=d2c(m)                         /* the character in question     */
    y=c2x(c)                         /* the hex representation        */
    if c.c>0 &,                      /* was found in the file         */
       datatype(c,'M')=0 Then Do     /* and is not a Latin letter     */
      other=other+c.c                /* increment count               */
      _=right(c.c,w)                 /* prepare output of count       */
      select                         /*make the character viewable.   */
       when c<<' ' | m==255 then say indent  "'"y"'x character count:" _
       when c==' '          then say indent   "blank character count:" _
       otherwise                 say indent "   " c 'character count:' _
       end
     end
   end
say 'file -----' dsn "----- has" other 'other characters.'

Output:

>WaA  Pa12 :&-: :äüÖ2< 20                                
 E8C44D8FF015674BCDEF                                    
 61100711200000000002                                    
file ----- PRIV.V100(TEST) ----- has 1 records.          
file ----- PRIV.V100(TEST) ----- has 20 characters.      
                     (Latin) letter  a count:  2         
                     (Latin) letter  A count:  1         
                     (Latin) letter  P count:  1         
                     (Latin) letter  W count:  1         
file ----- PRIV.V100(TEST) ----- has 5 (Latin) letters.  
                           other characters follow        
                     '00'x character count:  1           
                     '10'x character count:  1           
                     blank character count:  3           
                         & character count:  1           
                         - character count:  1           
                         : character count:  1           
                         : character count:  1           
                         ä character count:  1           
                         ü character count:  1           
                         Ö character count:  1           
                         1 character count:  1           
                         2 character count:  2           
file ----- PRIV.V100(TEST) ----- has 15 other characters.

Ring

textData = read("C:\Ring\ReadMe.txt")
ln =len(textData)
charCount = list(255)
totCount = 0
 
for i =1 to ln
    char = ascii(substr(textData,i,1))
    charCount[char] = charCount[char] + 1
    if char > 31 totCount = totCount + 1 ok
next
 
for i = 32 to 255
    if charCount[i] > 0 see char(i) + " = " + charCount[i] + " " + (charCount[i]/totCount)*100 + " %" + nl ok
next

RPL

« → text
  « { 26 } 0 CON
    1 text SIZE FOR j
       text j DUP SUB NUM
       IF DUP 97 ≥ OVER 122 ≤ AND THEN 32 - END
       IF DUP 65 ≥ OVER 90  ≤ AND THEN 64 - DUP2 GET 1 + PUT ELSE DROP END
    NEXT
    { }
    1 26 FOR j
       IF OVER j GET THEN LASTARG j 64 + CHR →TAG + END
    NEXT SWAP DROP              
» » 'AZFREQ' STO
'AZFREQ' DUP RCL →STR SWAP EVAL   @ have the program count its own letters
Output:
1: { :A: 5 :B: 1 :C: 2 :D: 9 :E: 17 :F: 5 :G: 4 :H: 4 :I: 4 :J: 5 :L: 1 :M: 1 :N: 12 :O: 6 :P: 5 :R: 7 :S: 3 :T: 16 :U: 7 :V: 3 :X: 5 :Z: 1 }

Ruby

def letter_frequency(file)
  letters = 'a' .. 'z'
  File.read(file) .
       split(//) .
       group_by {|letter| letter.downcase} .
       select   {|key, val| letters.include? key} .
       collect  {|key, val| [key, val.length]} 
end

letter_frequency(ARGV[0]).sort_by {|key, val| -val}.each {|pair| p pair}

example output, using the program file as input:

$ ruby letterFrequency.rb letterFrequency.rb
["e", 34]
["l", 20]
["t", 17]
["r", 14]
["a", 12]
["y", 9]
["c", 8]
["i", 7]
["v", 6]
["n", 6]
["f", 6]
["s", 6]
["d", 5]
["p", 5]
["k", 5]
["u", 4]
["o", 4]
["g", 3]
["b", 2]
["h", 2]
["q", 2]
["z", 1]
["w", 1]

Ruby 2.0

def letter_frequency(file)
  freq = Hash.new(0)
  file.each_char.lazy.grep(/[[:alpha:]]/).map(&:upcase).each_with_object(freq) do |char, freq_map|
    freq_map[char] += 1
  end
end

letter_frequency(ARGF).sort.each do |letter, frequency|
  puts "#{letter}: #{frequency}"
end

note that this version *should* use less memory, even on a gigantic file. This is done by using lazy enumerables, which ruby 2.0 introduces.

example output, using the (somewhat large) dictionary file as the input. Also note that this versions works on unicode text.

$ ruby letter_frequency.rb /usr/share/dict/words
A: 64439
B: 15526
C: 31872
D: 28531
E: 88833
F: 10675
G: 22712
H: 19320
I: 66986
J: 1948
K: 8409
L: 41107
M: 22508
N: 57144
O: 48944
P: 22274
Q: 1524
R: 57347
S: 90113
T: 53006
U: 26118
V: 7989
W: 7530
X: 2124
Y: 12652
Z: 3281
Å: 1
á: 10
â: 6
ä: 7
å: 3
ç: 5
è: 28
é: 144
ê: 6
í: 2
ñ: 8
ó: 8
ô: 2
ö: 16
û: 3
ü: 12

Ruby 2.7

Ruby 2.7 introduced "tally", which delivers a tally on anything enumerable.

p File.open("/usr/share/dict/words","r").each_char.tally

Run BASIC

open "c:\rbp101\public\textFile.txt" for input as #f
textData$ = input$(#f, lof( #f))
ln =len(textData$)
close #f

dim charCount( 255)
 
for i =1 to ln
   char            = asc(mid$(textData$,i,1))
   charCount(char) = charCount(char) + 1
   if char > 31 then totCount = totCount + 1
next i
 
for i = 32 to 255
if charCount(i) > 0 then print "Ascii:";using("###",i);" char:";chr$(i);" Count:";using("#######",charCount(i));" ";using("##.#",(charCount(i) / totCount) * 100);"%"
next i

Output uses this program to count itself:

Ascii: 32 char:  Count:     76 16.1%
Ascii: 34 char:" Count:     18  3.8%
Ascii: 35 char:# Count:     17  3.6%
Ascii: 36 char:$ Count:      6  1.3%
Ascii: 37 char:% Count:      1  0.2%
Ascii: 40 char:( Count:     16  3.4%
Ascii: 41 char:) Count:     16  3.4%
Ascii: 42 char:* Count:      1  0.2%
Ascii: 43 char:+ Count:      2  0.4%
Ascii: 44 char:, Count:      6  1.3%
Ascii: 46 char:. Count:      2  0.4%
Ascii: 47 char:/ Count:      1  0.2%
Ascii: 48 char:0 Count:      4  0.8%
Ascii: 49 char:1 Count:      8  1.7%
Ascii: 50 char:2 Count:      3  0.6%
Ascii: 51 char:3 Count:      2  0.4%
Ascii: 53 char:5 Count:      4  0.8%
Ascii: 58 char:: Count:      4  0.8%
Ascii: 59 char:; Count:      8  1.7%
Ascii: 61 char:= Count:      7  1.5%
Ascii: 62 char:> Count:      2  0.4%
Ascii: 65 char:A Count:      1  0.2%
Ascii: 67 char:C Count:     10  2.1%
Ascii: 68 char:D Count:      3  0.6%
Ascii: 70 char:F Count:      1  0.2%
Ascii: 92 char:\ Count:      3  0.6%
Ascii: 97 char:a Count:     19  4.0%
Ascii: 98 char:b Count:      2  0.4%
Ascii: 99 char:c Count:     17  3.6%
Ascii:100 char:d Count:      3  0.6%
Ascii:101 char:e Count:     13  2.7%
Ascii:102 char:f Count:     10  2.1%
Ascii:103 char:g Count:      3  0.6%
Ascii:104 char:h Count:     14  3.0%
Ascii:105 char:i Count:     24  5.1%
Ascii:108 char:l Count:      7  1.5%
Ascii:109 char:m Count:      2  0.4%
Ascii:110 char:n Count:     25  5.3%
Ascii:111 char:o Count:     21  4.4%
Ascii:112 char:p Count:      6  1.3%
Ascii:114 char:r Count:     17  3.6%
Ascii:115 char:s Count:      7  1.5%
Ascii:116 char:t Count:     38  8.0%
Ascii:117 char:u Count:     16  3.4%
Ascii:120 char:x Count:      7  1.5%

Rust

Works with all UTF-8 characters

use std::collections::btree_map::BTreeMap;
use std::{env, process};
use std::io::{self, Read, Write};
use std::fmt::Display;
use std::fs::File;

fn main() {
    let filename = env::args().nth(1)
        .ok_or("Please supply a file name")
        .unwrap_or_else(|e| exit_err(e, 1));

    let mut buf = String::new();
    let mut count = BTreeMap::new();

    File::open(&filename)
        .unwrap_or_else(|e| exit_err(e, 2))
        .read_to_string(&mut buf)
        .unwrap_or_else(|e| exit_err(e, 3));


    for c in buf.chars() {
        *count.entry(c).or_insert(0) += 1;
    }

    println!("Number of occurences per character");
    for (ch, count) in &count {
        println!("{:?}: {}", ch, count);
    }
}

#[inline]
fn exit_err<T>(msg: T, code: i32) -> ! where T: Display {
    writeln!(&mut io::stderr(), "{}", msg).expect("Could not write to stderr");
    process::exit(code)
}

Output when run on source file:

Number of occurences per character
'\n': 35
' ': 167
'!': 4
'\"': 10
'#': 1
'&': 4
'(': 25
')': 25
'*': 1
'+': 1
',': 12
'-': 1
'.': 10
'0': 1
'1': 3
'2': 2
'3': 2
':': 37
';': 13
'<': 1
'=': 4
'>': 2
'?': 1
'B': 2
'C': 1
'D': 2
'F': 2
'M': 2
'N': 1
'P': 1
'R': 1
'S': 1
'T': 5
'W': 1
'[': 1
']': 1
'_': 15
'a': 20
'b': 5
'c': 22
'd': 12
'e': 75
'f': 14
'g': 5
'h': 6
'i': 29
'k': 1
'l': 23
'm': 13
'n': 36
'o': 28
'p': 17
'r': 45
's': 33
't': 42
'u': 24
'v': 2
'w': 8
'x': 6
'y': 4
'{': 9
'|': 6
'}': 9

S-BASIC

Because S-BASIC lacks an EOF function, some extra care is required to avoid reading beyond the end of file. (CP/M text files are normally terminated with a Ctrl-Z byte, but not all text editors enforce this convention if the file would otherwise end on a sector boundary.)

$constant EOF = 1AH       rem  normal end-of-file marker

rem  Convert character to upper case
function upcase(ch = char) = char
   if ch >= 'a' and ch <= 'z' then
       ch = ch - 32
end = ch

rem  Convert string to all upper case characters
function allcaps(source = string) = string
   var p = integer
   for p = 1 to len(source) do
       mid(source,p,1) = upcase(mid(source,p,1))
   next p
end = source

comment
  Preserve console and printer channels (#0 and #1)
  Channel #2 declared as sequential ASCII
end
files d, d, sa(1)

var ch = char
var i = integer
based errcode = integer
base errcode at 103H       rem  S-BASIC stores run-time error code here
var filename = string
var total = real
dim real freq(26)

input "Name of text file to process: "; filename
filename = allcaps(filename)
open #2; filename
on error goto 7_trap    rem  In case input file lacks terminating ^Z

rem  Initialize letter counts to zero
for i = 1 to 26
  freq(i) = 0
next i

rem  Process the file
total = 0
input3 #2; ch
while ch <> EOF do
    begin
        ch = upcase(ch);
        if ch >= "A" and ch <= "Z" then
            begin
                freq(ch - 64) = freq(ch - 64) + 1
                total = total + 1
            end
        input3 #2; ch
    end

goto 8_done      rem  Jump around error trap

7_trap	if errcode <> 15 then 
	    begin
	        print "Runtime error = ";errcode
		goto 9_exit
	    end
	rem  otherwise fall through on attempted read past EOF (err = 15)
8_done	
	close #2

rem  Report results
print "Letter   Count   Percent"
for I = 1 to 26
    print chr(i+64);"      ";
    print using " ##,###"; freq(i);
    print using "    ##.#"; freq(i) / total * 100
next i
    
9_exit
end
Output:

With Lincoln's Second Inaugural Address used as input

Letter  Count   Percent
A         101       8.8
B          14       1.2
C          31       2.7
D          59       5.1
E         165      14.3
F          27       2.3
G          28       2.4
H          80       7.0
I          68       5.9
J           0       0.0
K           3       0.3
L          42       3.7
M          13       1.1
N          78       6.8
O          93       8.1
P          15       1.3
Q           1       0.1
R          79       6.9
S          44       3.8
T         126      11.0
U          21       1.8
V          23       2.0
W          28       2.4
X           0       0.0
Y          11       1.0
Z           0       0.0

Scala

import io.Source.fromFile

def letterFrequencies(filename: String) = 
  fromFile(filename).mkString groupBy (c => c) mapValues (_.length)

Scheme

Using guile scheme 2.0.11.

Note that this prints the scheme representations of characters in no particular order.

(use-modules (ice-9 format))

(define (char-freq port table)
  (if
   (eof-object? (peek-char port))
   table
   (char-freq port (add-char (read-char port) table))))

(define (add-char char table)
  (cond
   ((null? table) (list (list char 1)))
   ((eq? (caar table) char) (cons (list char (+ (cadar table) 1)) (cdr table)))
   (#t (cons (car table) (add-char char (cdr table))))))

(define (format-table table)
  (for-each (lambda (t) (format #t "~10s~10d~%" (car t) (cadr t))) table))

(define (print-freq filename)
  (format-table (char-freq (open-input-file filename) '())))

(print-freq "letter-frequency.scm")

Output when reading own source:

#\(               45
#\u                5
#\s                9
#\e               47
#\-               19
#\m                9
#\o               16
#\d               19
#\l               25
#\space           83
#\i               15
#\c               28
#\9                1
#\f               20
#\r               39
#\a               47
#\t               36
#\)               45
#\newline         21
#\n               15
#\h               14
#\q                7
#\p                9
#\b               16
#\j                1
#\?                3
#\k                1
#\1                4
#\+                1
#\#                2
#\"                4
#\~                3
#\0                2
#\%                1
#\'                1
#\y                1
#\.                1

An implementation for CHICKEN scheme:

(with-input-from-string "foobar"
  (lambda ()
    (port-fold (lambda (x s)
                 (alist-update x
                               (add1 (alist-ref x s eq? 0))
                               s))
               '()
               read-char)))

which shows: ((#\f . 1) (#\o . 2) (#\b . 1) (#\a . 1) (#\r . 1))

Seed7

$ include "seed7_05.s7i";
 
const type: charHash is hash [char] integer;
 
const proc: main is func
  local
    var charHash: numberOfChars is charHash.EMPTY_HASH;
    var char: ch is ' ';
  begin
    ch := getc(IN);
    while ch <> EOF do
      if ch in numberOfChars then
        incr(numberOfChars[ch]);
      else
        numberOfChars @:= [ch] 1;
      end if;
      ch := getc(IN);
    end while;
    for ch range sort(keys(numberOfChars)) do
      writeln(ch <& " " <& numberOfChars[ch]);
    end for;
  end func;

Output when the program uses itself as input:

 22
  129
" 4
$ 1
& 2
' 2
( 6
) 6
. 2
0 1
...
s 21
t 9
u 9
v 2
w 3
y 2

SenseTalk

put file "~/Documents/addresses.csv" into source

repeat with each character of source
	if it is a controlChar then next repeat -- skip control characters
	if it is a lowercase then put "." after it -- make keys distinct
	add 1 to counts.(it)
end repeat

repeat with each (theChar, count) in counts
	put char 1 of theChar & " —> " & count
end repeat

Output:

  —> 2862
" —> 11180
# —> 109
& —> 58
, —> 5646
- —> 2009
. —> 1629
/ —> 1000
0 —> 1496
1 —> 1665
2 —> 1487
3 —> 1481
4 —> 1405
5 —> 1416
6 —> 1260
7 —> 1499
8 —> 1323
9 —> 1349
: —> 500
@ —> 500
_ —> 127
A —> 558
a —> 4082
B —> 290
b —> 455
C —> 572
c —> 2387
D —> 273
d —> 1230
E —> 265
e —> 4493
F —> 177
f —> 392
G —> 146
g —> 911
H —> 239
h —> 1699
I —> 235
i —> 2935
J —> 212
j —> 147
K —> 131
k —> 646
L —> 302
l —> 2602
M —> 428
m —> 1912
N —> 319
n —> 3237
O —> 136
o —> 4018
P —> 294
p —> 1141
Q —> 6
q —> 228
R —> 288
r —> 3124
S —> 600
s —> 2229
T —> 196
t —> 3328
U —> 21
u —> 899
V —> 65
v —> 508
W —> 222
w —> 1937
X —> 34
x —> 153
Y —> 99
y —> 858
Z —> 14
z —> 145

Sidef

func letter_frequency(File file) {
    file.read.chars.grep{.match(/[[:alpha:]]/)} \
        .group_by {|letter| letter.downcase}    \
        .map_val  {|_, val| val.len}            \
        .sort_by  {|_, val| -val}
}
 
var top = letter_frequency(File(__FILE__))
top.each{|pair| say "#{pair[0]}: #{pair[1]}"}
Output:
e: 22
l: 17
a: 16
t: 14
r: 14
p: 12
f: 8
i: 8
n: 7
c: 6
u: 6
o: 6
v: 6
y: 5
s: 5
h: 3
w: 2
q: 2
b: 2
m: 2
g: 2
d: 1

SIMPOL

Example: open a text file and compute letter frequency.

constant iBUFSIZE 500

function main(string filename)
  fsfileinputstream fpi
  integer e, i, aval, zval, cval
  string s, buf, c
  array chars

  e = 0
  fpi =@ fsfileinputstream.new(filename, error=e)
  if fpi =@= .nul
    s = "Error, file """ + filename + """ not found{d}{a}"
  else
    chars =@ array.new()
    aval = .charval("a")
    zval = .charval("z")
    i = 1
    while i <= 26
      chars[i] = 0
      i = i + 1
    end while
    buf = .lcase(fpi.getstring(iBUFSIZE, 1))
    while not fpi.endofdata and buf > ""
      i = 1
      while i <= .len(buf)
        c = .substr(buf, i, 1)
        cval = .charval(c)
        if cval >= aval and cval <= zval
          chars[cval - aval + 1] = chars[cval - aval + 1] + 1
        end if
        i = i + 1
      end while
      buf = .lcase(fpi.getstring(iBUFSIZE, 1))
    end while

    s = "Character counts for """ + filename + """{d}{a}"
    i = 1
    while i <= chars.count()
      s = s + .char(aval + i - 1) + ": " + .tostr(chars[i], 10) + "{d}{a}"
      i = i + 1
    end while
  end if
end function s

As this was being created I realized that in [SIMPOL] I wouldn't have done it this way (in fact, I wrote it differently the first time and had to go back and change it to use an array afterward). In [SIMPOL] we would have used the set object. It acts similarly to a single-dimensional array, but can also use various set operations, such as difference, unite, intersect, etc. One of th einteresting things is that each unique value is stored only once, and the number of duplicates is stored with it. The sample then looks a little cleaner:

constant iBUFSIZE 500

function main(string filename)
  fsfileinputstream fpi
  integer e, i, aval, zval
  string s, buf, c
  set chars

  e = 0
  fpi =@ fsfileinputstream.new(filename, error=e)
  if fpi =@= .nul
    s = "Error, file """ + filename + """ not found{d}{a}"
  else
    chars =@ set.new()
    aval = .charval("a")
    zval = .charval("z")
    buf = .lcase(fpi.getstring(iBUFSIZE, 1))
    while not fpi.endofdata and buf > ""
      i = 1
      while i <= .len(buf)
        c = .substr(buf, i, 1)
        if .charval(c) >= aval and .charval(c) <= zval
          chars.addvalue(c)
        end if
        i = i + 1
      end while
      buf = .lcase(fpi.getstring(iBUFSIZE, 1))
    end while

    s = "Character counts for """ + filename + """{d}{a}"
    i = 1
    while i <= chars.count()
      s = s + chars[i] + ": " + .tostr(chars.valuecount(chars[i]), 10) + "{d}{a}"
      i = i + 1
    end while
  end if
end function s

The final stage simply reads the totals for each character. One caveat, if a character is unrepresented, then it will not show up at all in this second implementation.

Smalltalk

Make it a bag of characters and get the counts:

Works with: Smalltalk/X
bagOfChars := 'someFile' asFilename contentsAsString asBag.
bag sortedCounts 
    select:[:assoc | assoc value isLetter ]
    thenDo:[:assoc | assoc printCR].

If the file is huge, you may not want to read it in as a big string first, but feed the chars linewise into the bag:

bagOfChars := Bag new.
'someFile' asFilename readingLinesDo:[:eachLine | bagOfChars addAll:eachLine].
bag sortedCounts ...

To show all counts (as opposed to selecting the letter counts only), replace the "select:thenDo:" by a simple "do:", as in:

bag sortedCounts do:[:assoc | assoc printCR].

or even shorter:

bag sortedCounts do:#printCR.
Output:
27->e
20->n
16->o
16->u
16->d
...

If you prefer seeing the character first, followed by the count, replace the do-loop's action with:

... do:[:assoc | '%s -> %s\n' printf:{assoc value . assoc key} on:Stdout ].
Output:
e -> 27
n -> 20
u -> 16
d -> 16
...

Swift

import Foundation

let dictPath: String

switch CommandLine.arguments.count {
case 2:
  dictPath = CommandLine.arguments[1]
case _:
  dictPath = "/usr/share/dict/words"
}

let wordsData = FileManager.default.contents(atPath: dictPath)!
let allWords = String(data: wordsData, encoding: .utf8)!
let words = allWords.components(separatedBy: "\n")
let counts = words.flatMap({ $0.map({ ($0, 1) }) }).reduce(into: [:], { $0[$1.0, default: 0] += $1.1 })

for (char, count) in counts {
  print("\(char): \(count)")
}

Tcl

proc letterHistogram {fileName} {
    # Initialize table (in case of short texts without every letter)
    for {set i 97} {$i<=122} {incr i} {
        set frequency([format %c $i]) 0
    }
    # Iterate over characters in file
    set f [open $fileName]
    foreach c [split [read $f] ""] {
        # Count them if they're alphabetic
        if {[string is alpha $c]} {
            incr frequency([string tolower $c])
        }
    }
    close $f
    # Print the histogram
    parray frequency
}

letterHistogram the/sample.txt

TUSCRIPT

$$ MODE TUSCRIPT
words = REQUEST ("http://www.puzzlers.org/pub/wordlists/unixdict.txt")

DICT letters create
MODE {}
COMPILE
LOOP word=words
 letters=SPLIT (word,|":?:")
 LOOP letter=letters
  DICT letters ADD/QUIET/COUNT letter
 ENDLOOP
ENDLOOP
ENDCOMPILE
DICT letters unload letter,size,cnt

index    =DIGIT_INDEX (cnt)
index    =REVERSE (index)
letter   =INDEX_SORT (letter,index)
cnt      =INDEX_SORT (cnt,index)
frequency=JOIN (letter," --- ",cnt)

*{frequency}

Output:

e --- 20144
a --- 16421
i --- 13980
r --- 13436
t --- 12836
o --- 12738
n --- 12097
s --- 10210
l --- 10061
c --- 8216
u --- 6489
m --- 5828
d --- 5799
p --- 5516
h --- 5208
g --- 4129
b --- 4115
y --- 3633
f --- 2662
w --- 1968
k --- 1925
v --- 1902
x --- 617
z --- 433
j --- 430
q --- 378
' --- 105
. --- 6
& --- 6
1 --- 2
9 --- 1
8 --- 1
7 --- 1
6 --- 1
5 --- 1
4 --- 1
3 --- 1
2 --- 1
0 --- 1

TXR

TXR Extraction Language plus TXR Lisp

@(do (defvar h (hash :equal-based)))
@(repeat)
@(coll :vars ())@\
  @{letter /[A-Za-z]/}@(filter :upcase letter)@\
  @(do (inc [h letter 0]))@\
@(end)
@(end)
@(do (dohash (key value h)
       (format t "~a: ~a\n" key value)))
Output:
$ ./txr letterfreq.txr /usr/share/dict/words
A: 64123
B: 15524
C: 31569
[ ... abridged ... ]
X: 2124
Y: 12507
Z: 3238

TXR Lisp

(let* ((s (open-file "/usr/share/dict/words" "r"))
       (chrs [keep-if* chr-isalpha (gun (get-char s))])
       (h [group-reduce (hash) chr-toupper (op succ @1) chrs 0]))
  (dohash (key value h)
    (put-line `@key: @value`)))

Vala

Library: Gee

Counts every character except new line character.

using Gee;

void main(string[] args){
    string filename = args[1];
    var file = FileStream.open(filename, "r");

    var	counter	= new HashMap<char, int>();

    string line = file.read_line();
    while (line != null){
        for (int x = 0;	x < line.length; x++){
            counter[line[x]] = counter[line[x]] + 1;
	}
        line = file.read_line();
    }

    foreach (var elem in counter.entries){
	stdout.printf("%c occured %d times\n", elem.key, elem.value);
    }
}

Sample output (run on its own source code) with several lines omitted:

v occured 5 times
, occured 4 times
w occured 2 times
	 occured 19 times
S occured 1 times
1 occured 2 times
! occured 1 times
k occured 1 times
l occured 22 times

VBA

Public Sub LetterFrequency(fname)
'count number of letters in text file "fname" (ASCII-coded)
'note: we count all characters but print only the letter frequencies

Dim Freqs(255) As Long
Dim abyte As Byte
Dim ascal as Byte 'ascii code for lowercase a
Dim ascau as Byte 'ascii code for uppercase a

'try to open the file
On Error GoTo CantOpen
Open fname For Input As #1
On Error GoTo 0

'initialize
For i = 0 To 255
  Freqs(i) = 0
Next i

'process file byte-per-byte
While Not EOF(1)
 abyte = Asc(Input(1, #1))
 Freqs(abyte) = Freqs(abyte) + 1
Wend
Close #1

'add lower and upper case together and print result
Debug.Print "Frequencies:"
ascal = Asc("a")
ascau = Asc("A")
For i = 0 To 25
  Debug.Print Chr$(ascal + i), Freqs(ascal + i) + Freqs(ascau + i)
Next i
Exit Sub

CantOpen:
  Debug.Print "can't find or read the file "; fname
  Close
End Sub

Output:

LetterFrequency "d:\largetext.txt"
Frequencies:
a              24102 
b              4985 
c              4551 
d              19127 
e              61276 
f              2734 
g              10661 
h              8243 
i              21589 
j              4904 
k              7186 
l              12026 
m              7454 
n              31963 
o              19021 
p              4960 
q              37 
r              21166 
s              13403 
t              21090 
u              6117 
v              8612 
w              5017 
x              168 
y              299 
z              4159 

VBScript

filepath = "SPECIFY FILE PATH HERE"

Set objfso = CreateObject("Scripting.FileSystemObject")
Set objdict = CreateObject("Scripting.Dictionary")
Set objfile = objfso.OpenTextFile(filepath,1)

txt = objfile.ReadAll

For i = 1 To Len(txt)
	char = Mid(txt,i,1)
	If objdict.Exists(char) Then
		objdict.Item(char) = objdict.Item(char) + 1
	Else
		objdict.Add char,1
	End If
Next

For Each key In objdict.Keys
	WScript.StdOut.WriteLine key & " = " & objdict.Item(key)
Next	

objfile.Close
Set objfso = Nothing
Set objdict = Nothing

Vedit macro language

File_Open("c:\txt\a_text_file.txt")
Update()

for (#1='A'; #1<='Z'; #1++) {
    Out_Reg(103) Char_Dump(#1,NOCR) Out_Reg(CLEAR)
    #2 = Search(@103, BEGIN+ALL+NOERR)
    Message(@103) Num_Type(#2)
}

Example output:

A   76
B   23
C   51
D   64
E  192
F   51
G   32
H   59
I  146
J    1
K    9
L   73
M   34
N   94
O  113
P   27
Q    1
R   92
S   89
T  138
U   63
V   26
W   35
X   16
Y   16
Z    2

V (Vlang)

import os
struct LetterFreq {
    rune int
    freq int
}

fn main(){
    file := os.read_file('unixdict.txt')?
    mut freq := map[rune]int{}
    for c in file {
        freq[c]++
    }
    mut lf := []LetterFreq{}
    for k,v in freq {
        lf << LetterFreq{u8(k),v}
    }
    lf.sort_with_compare(fn(a &LetterFreq, b &LetterFreq)int{
        if a.freq > b.freq {
            return -1
        }
        if a.freq < b.freq {
            return 1
        }
        return 0
    })
    for f in lf {
        println('${u8(f.rune).ascii_str()} ${f.rune} $f.freq')
    }
}
Output:
 D 25103

 A 25103
e 65 20144
a 61 16421
i 69 13980
r 72 13436
t 74 12836
o 6F 12738
n 6E 12097
s 73 10210
l 6C 10061
c 63 8216
u 75 6489
m 6D 5828
d 64 5799
p 70 5516
h 68 5208
g 67 4129
b 62 4115
y 79 3633
f 66 2662
w 77 1968
k 6B 1925
v 76 1902
x 78 617
z 7A 433
j 6A 430
q 71 378
' 27 105
& 26 6
. 2E 6
1 31 2
8 38 1
7 37 1
6 36 1
5 35 1
4 34 1
3 33 1
2 32 1
0 30 1
9 39 1

Whitespace

push 127
; Initialize a slot in the heap for each ASCII character.
0:
    dup
    push 0
    store
    push 1
    sub
    dup
    jn 1
    jump 0
; Read until EOF, incrementing the relevant heap slot.
1:
    push 0
    dup
    ichr
    load
    dup
    jn 2 ; Done reading, proceed to print.
    dup
    load
    push 1
    add
    store
    jump 1
; Stack is [-1 -1], but [0] would be nice.
2:
    sub
; Print characters with tallies greater than 0.
3:
    push 1
    add
    dup
    push 128
    sub
    jz 4 ; All done.
    dup
    load
    jz 3 ; Don't print if no occurrences.
    dup
    ochr ; Display the character,
    push 32
    ochr ; a space,
    dup
    load
    onum ; its frequency,
    push 10
    ochr ; and a newline.
    jump 3
4:
    pop
    exit
Output:
$ cat freq.ws | wspace freq.ws
	 64

 55
  119

Wren

Library: Wren-fmt

As we have a copy to hand, we count the number of letters in the MIT 10000 word list which apparently contains nothing other than lower case letters.

import "io" for File
import "./fmt" for Fmt

var text = File.read("mit10000.txt")
var freqs = List.filled(26, 0)
for (c in text.codePoints) {
    if (c >= 97 && c <= 122) {
        freqs[c-97] = freqs[c-97] + 1
    }
}
var totalFreq = freqs.reduce { |sum, f| sum + f }
System.print("Frequencies of letters in mit10000.txt:")
System.print("\n    freq     \%")
System.print("----------------")

for (i in 0..25) {
    Fmt.print("$c  $5d  $6.2f", i+97, freqs[i], freqs[i]/totalFreq * 100)
}
System.print("   -----  ------")
Fmt.print("   $5d  100.00", totalFreq)

Fmt.print("\nTotal characters in text file = $d minus 10000 \\n's = $d", text.count, totalFreq)
Output:
Frequencies of letters in mit10000.txt:

    freq     %
----------------
a   5378    8.16
b   1141    1.73
c   3025    4.59
d   2507    3.81
e   7601   11.54
f    927    1.41
g   1717    2.61
h   1429    2.17
i   5461    8.29
j    183    0.28
k    592    0.90
l   3231    4.90
m   1912    2.90
n   4822    7.32
o   4252    6.45
p   2027    3.08
q    123    0.19
r   4860    7.38
s   5085    7.72
t   4760    7.23
u   1939    2.94
v    849    1.29
w    632    0.96
x    264    0.40
y   1027    1.56
z    136    0.21
   -----  ------
   65880  100.00

Total characters in text file = 75880 minus 10000 \n's = 65880

XPL0

This takes advantage of DOS's ability to redirect input from a file to the keyboard. The input file must be terminated with an end-of-file character ($1A). Usage: count <filename.ext

include c:\cxpl\codes;          \intrinsic 'code' declarations
int A(256), C, I;
[for C:= 0 to 256-1 do A(C):= 0;
repeat  C:= ChIn(1);            \device 1 doesn't buffer nor echo chars
        A(C):= A(C)+1;          \count character
until   C=\EOF\$1A;
C:= 0;
for I:= 0 to 128-1 do           \only show 7-bit ASCII
        [ChOut(0, \tab\9);
        case C of
          $0A: ChOut(6, $19);   \line feed = down arrow
          $0D: ChOut(6, $1B)    \carriage return = left arrow
        other  ChOut(6, C);     \all other characters display on device 6
        ChOut(0, ^ );
        IntOut(0, A(C));        \show count
        C:= C+16;               \columnar order
        if (I&7) = 7 then [CrLf(0);  C:= C-8*16+1];
        ];
]

Example output of count.xpl counting itself:

Yabasic

dim ascCodes(255)

f = open("unixdict.txt", "r")

if f then
    while(not eof(#f)) 
        line input #f a$
        for i = 1 to len(a$)
            c = asc(mid$(a$, i, 1))
            ascCodes(c) = ascCodes(c) + 1
        next
    wend
    for i = 1 to 255
        c = ascCodes(i)
        if c print chr$(i), " = ", c
    next
    close #f
end if

zkl

fcn ccnt(textInBitBucket){
   letters:=["a".."z"].pump(List().write,0); // array of 26 zeros
   textInBitBucket.howza(0).pump(Void,'wrap(c){  // pump text as ints
      if(97<=c<=122)     c-=97;
      else if(65<=c<=90) c-=65;
      else return(Void.Skip);
      letters[c]+=1
   });
   sum:=letters.sum(); println(sum," letters");
   letters.enumerate().pump(List,'wrap([(c,n)]){
      "%s(%d:%d%)".fmt((c+65).toChar(),n,n*100/sum)})
   .concat(",").println();
}

ccnt(Data(0,Int,"This is a test"));
ccnt(File("dict.txt").read());
Output:
11 letters
A(1:9%),B(0:0%),C(0:0%),D(0:0%),E(1:9%),F(0:0%),G(0:0%),H(1:9%),I(2:18%),J(0:0%),K(0:0%),L(0:0%),M(0:0%),N(0:0%),O(0:0%),P(0:0%),Q(0:0%),R(0:0%),S(3:27%),T(3:27%),U(0:0%),V(0:0%),W(0:0%),X(0:0%),Y(0:0%),Z(0:0%)

181171 letters
A(16421:9%),B(4115:2%),C(8216:4%),D(5799:3%),E(20144:11%),F(2662:1%),G(4129:2%),H(5208:2%),I(13980:7%),J(430:0%),K(1925:1%),L(10061:5%),M(5828:3%),N(12097:6%),O(12738:7%),P(5516:3%),Q(378:0%),R(13436:7%),S(10210:5%),T(12836:7%),U(6489:3%),V(1902:1%),W(1968:1%),X(617:0%),Y(3633:2%),Z(433:0%)

Zoea

program: letter_frequency
  input: 'cbcacb'                  # can be literal value, stdin or file url at runtime
  derive: [[a,1],[b,2],[c,3]]
  output: 'a : 1\nb : 2\nc : 3\n'

Zoea Visual

Letter Frequency