How can I count the frequency of characters in a string and then output them in sort of a table?
For example, if I input the word \"happy\" the result would be
Use list comprehension, no need for any imports or sorting.
[ (x,c) | x<-['A'..'z'], let c = (length.filter (==x)) "happy", c>0 ]
Result:
[('a',1),('h',1),('p',2),('y',1)]
Above is the filtered and rewritten (only character with count > 0) from:
[(x,(length.filter (==x)) "happy" ) | x<-['A'..'z']]
Explanation:
//Count the frequency of character in a string
package waytocreateobject;
import java.util.Scanner;
public class Freqchara {
public static void main(String[] args) {
int c = 0, x = 0, loop = 26, space = 0;
int count[] = new int[loop];
//Arrays.fill(count, x);
Scanner sc = new Scanner(System.in);
String str =sc.nextLine();
char[] charr = str.toCharArray();
int aa = str.length();
//System.out.println(str.charAt(10));
//System.out.println(str.charAt(11));
for (int mm = 0; mm < aa; mm++) {
if (str.charAt(c) != '\0') { //Considering characters from 'a' to 'z' only and ignoring others.
if ((str.charAt(c) >= 'a') && (str.charAt(c) <= 'z')) {
x = (int) str.charAt(c) - (int) 'a';
// System.out.println(x);
count[x] = count[x] + 1;
}
c++;
} else {}
}
// printing all the charcter
int i = 97;
for (int j = 0; j < loop; j++) {
char ch = (char) (i + j);
System.out.println(ch + " occurs " + count[j] + " times in the string");
}
System.out.println(" occurs " + space);
}
}
func xs = map (\a -> (head a, length a)) $ group $ sort xs
The simplest solution is to use a Data.Map to store the intermediate mapping from character to frequency. You can then construct the counts easily using fromListWith. Since Data.Map
is sorted, you get them in ASCII order for free.
λ> :m + Data.Map
λ> let input = "happy"
λ> toList $ fromListWith (+) [(c, 1) | c <- input]
[('a',1),('h',1),('p',2),('y',1)]
So what's happening here?
The idea is to build a Data.Map
(a tree map) using the characters as keys and the frequencies as values.
First, we take the input string and make tuples of each character with a 1
to indicate one occurrence.
λ> [(c, 1) | c <- input]
[('h',1),('a',1),('p',1),('p',1),('y',1)]
Next, we use fromListWith
to build a sorted map from these key-value pairs by repeatedly inserting each key-value pair into a map. We also give it a function which will be used when a key was already in the map. In our case, we use (+)
so that when a character is seen multiple times, we add the count to the existing sum.
Finally we covert the map back into a list of key-value tuples using toList
.
import Data.Array (Ix, accumArray, assocs)
eltDist :: (Bounded a, Ix a, Eq b, Num b) => [a] -> [(a, b)]
eltDist str = filter ((/=0) . snd ) $
assocs (accumArray (+) 0 (minBound, maxBound) [(i, 1) | i <- str])
"minBound" and "maxBound" are going to depend on the range of the type inferred for i. For Char it will be 0 - 1,114,111, which is extravagant but not impossible. It would be especially convenient if you were counting Unicode chars. If you are only interested in ASCII strings, then (0, 255) would do. A nice thing about arrays is that they can be indexed by any type that can be mapped to an integer. See Ix.
assocs pulls the indices and counts out of the array into a list of pairs and filter disposes of the unused ones.
There's probably something shorter, but this works:
Prelude> import Data.List
Prelude Data.List> map (\x -> (head x, length x)) $ group $ sort "happy"
[('h',1),('a',1),('p',2),('y',1)]