# Finding the frequency of letters in a string

Given the following string:

sentence = "Never in the delirious dream of a disordered brain could
anything more savage, more appalling, more hellish, be conceived than
that dark form and savage face which broke upon us out of the wall of
fog";


I am trying to find the frequency of occurrence of each letter. Working towards this, I have find the occurrence of each letter by:

CountLettersSorted[y_] :=
Reverse[SortBy[
Tally[Characters[
StringReplace[
ToLowerCase[y], {"," -> "", " " -> "", "." -> "",
"-" -> ""}]]], Last]];


Giving:

{{"e", 39}, {"a", 35}, {"s", 26}, {"n", 25}, {"o", 24}, {"l",
24}, {"t", 23}, {"d", 21}, {"u", 17}, {"i", 17}, {"h", 17}, {"r",
14}, {"m", 13}, {"w", 11}, {"c", 11}, {"y", 9}, {"b", 9}, {"p",
7}, {"k", 7}, {"v", 6}, {"g", 6}, {"f", 3}}


Now I'm trying to define a function f that can be mapped to this list ie:

f:= #/Length[string[s]]
findingfrequency=Map[f,#]


But this is not working, any ideas?

• If you use # in your code, you also need & (this marks the end of the anonymous function). For your specific case, I would suggest ReverseSort[Counts[Characters[…]]] to get an association of the counts. Then all you need is counts/Length["..."] to get the frequencies. (The advantage of an association here is that the keys (the letters) are ignored for many operations, so dividing by the length leaves them alone) Commented Nov 11, 2018 at 12:39

## 6 Answers

Why not use LetterCounts

LetterCounts[sentence, IgnoreCase -> True] // KeySort

N[#]/Total[#] &[%]

<|"a" -> 16, "b" -> 3, "c" -> 5, "d" -> 9, "e" -> 19, "f" -> 6,
"g" -> 5, "h" -> 9, "i" -> 10, "k" -> 2, "l" -> 8, "m" -> 5,
"n" -> 10, "o" -> 15, "p" -> 3, "r" -> 12, "s" -> 6, "t" -> 7,
"u" -> 5, "v" -> 4, "w" -> 2, "y" -> 1|>

<|"a" -> 0.0987654, "b" -> 0.0185185, "c" -> 0.0308642,
"d" -> 0.0555556, "e" -> 0.117284, "f" -> 0.037037, "g" -> 0.0308642,
"h" -> 0.0555556, "i" -> 0.0617284, "k" -> 0.0123457,
"l" -> 0.0493827, "m" -> 0.0308642, "n" -> 0.0617284,
"o" -> 0.0925926, "p" -> 0.0185185, "r" -> 0.0740741,
"s" -> 0.037037, "t" -> 0.0432099, "u" -> 0.0308642,
"v" -> 0.0246914, "w" -> 0.0123457, "y" -> 0.00617284|>


BTW, your sentence does not give 39 "e"s.

Use LetterCounts as in Αλέξανδρος Ζεγγ's answer:

lc = KeySort @ LetterCounts[sentence, IgnoreCase -> True]


To get the frequencies you can use Normalize:

f = Normalize[#, Total] &;

f @ lc


N @ f @ lc


Does this not accomplish what you're after?

Reverse[SortBy[
Tally[ToLowerCase@
StringCases[sentence, LetterCharacter]], #[[2]] &]]


Not totally sure if this is what you want:

    tallyChars[sentence_String] := Module[{work},
work = StringCases[Characters[sentence],
head___ ~~ LetterCharacter ~~ tail___] /. {} -> Nothing;
work = Flatten@(ToLowerCase /@ work);
SortBy[Tally[work], Last] // Reverse
]


This can be done shorter, but so it is easy to read:

Step1: get the letter characters and delete the {} coming form punctuation marks etc. Step2: Convert to Lowercase and flatten the list Step3: Sorting

You can then use the function as tallyChars /@ listOfStrings

remark: your example sentence has only 19 times the letter "e".

Tally @ Sort @ Apply[Join] @
StringCases[
Characters @ ToLowerCase @ sentence,
CharacterRange["a", "z"]]


{{"a", 16}, {"b", 3}, {"c", 5}, {"d", 9}, {"e", 19}, {"f", 6}, {"g", 5}, {"h", 9}, {"i", 10}, {"k", 2}, {"l", 8}, {"m", 5}, {"n", 10}, {"o", 15}, {"p", 3}, {"r", 12}, {"s", 6}, {"t", 7}, {"u", 5}, {"v", 4}, {"w", 2}, {"y", 1}}

Or

res =
KeyMap[FromCharacterCode] @ Counts @ Sort @
Select[Between[{97, 122}]] @ ToCharacterCode @ ToLowerCase @ sentence


<|"a" -> 16, "b" -> 3, "c" -> 5, "d" -> 9, "e" -> 19, "f" -> 6, "g" -> 5, "h" -> 9, "i" -> 10, "k" -> 2, "l" -> 8, "m" -> 5, "n" -> 10, "o" -> 15, "p" -> 3, "r" -> 12, "s" -> 6, "t" -> 7, "u" -> 5, "v" -> 4, "w" -> 2, "y" -> 1|>

To get the frequencies:

res / Total[res]


<|"a" -> 8/81, "b" -> 1/54, "c" -> 5/162, "d" -> 1/18, "e" -> 19/162, "f" -> 1/27, "g" -> 5/162, "h" -> 1/18, "i" -> 5/81, "k" -> 1/81, "l" -> 4/81, "m" -> 5/162, "n" -> 5/81, "o" -> 5/54, "p" -> 1/54, "r" -> 2/27, "s" -> 1/27, "t" -> 7/162, "u" -> 5/162, "v" -> 2/81, "w" -> 1/81, "y" -> 1/162|>

Or, as percentages,

res / Total[res] * 100. // Round[#, 0.1] & // ReverseSort // Normal // Column


sentence = "Never in the delirious dream of a disordered brain could
anything more savage, more appalling, more hellish, be conceived than
that dark form and savage face which broke upon us out of the wall of
fog";

res=StringCases[ToLowerCase@sentence, #] & /@ Alphabet[] // Map[Tally] //
Flatten[#, 1] & // SortBy[First]

t = Total[res[[All, 2]]];
SubsetMap[#/t &, res, {All, 2}]


{{"a", 8/81}, {"b", 1/54}, {"c", 5/162}, {"d", 1/18}, {"e", 19/
162}, {"f", 1/27}, {"g", 5/162}, {"h", 1/18}, {"i", 5/81}, {"k", 1/
81}, {"l", 4/81}, {"m", 5/162}, {"n", 5/81}, {"o", 5/54}, {"p", 1/
54}, {"r", 2/27}, {"s", 1/27}, {"t", 7/162}, {"u", 5/162}, {"v", 2/
81}, {"w", 1/81}, {"y", 1/162}}

Also try:

Transpose[{res[[All, 1]], PercentForm /@ N[res[[All, 2]] /t]}]


... a bit slow (result shows counts only)

Scan[If[MemberQ[Alphabet[], #], Sow[#, #], Nothing] &,
Characters@ToLowerCase@sentence] // Reap // Last // Map[Tally] //
SortBy[First] // Flatten[#, 1] &
`

Result

{{"a", 16}, {"b", 3}, {"c", 5}, {"d", 9}, {"e", 19}, {"f", 6}, {"g",
5}, {"h", 9}, {"i", 10}, {"k", 2}, {"l", 8}, {"m", 5}, {"n", 10}, {"o", 15}, {"p", 3}, {"r", 12}, {"s", 6}, {"t", 7}, {"u", 5}, {"v", 4}, {"w", 2}, {"y", 1}}