How to find the frequency of characters in a string in Haskell?

前端 未结 7 1273
谎友^
谎友^ 2020-12-11 15:08

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

相关标签:
7条回答
  • 2020-12-11 15:14

    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:

    • Make a list of all characters that match a given character (A..z).
    • For each character, count this list (==length)
    • Put this count in a tuple with the character
    0 讨论(0)
  • 2020-12-11 15:20
    //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);
        }
    }
    
    0 讨论(0)
  • 2020-12-11 15:21

    func xs = map (\a -> (head a, length a)) $ group $ sort xs

    0 讨论(0)
  • 2020-12-11 15:23

    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.

    0 讨论(0)
  • 2020-12-11 15:23
    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.

    0 讨论(0)
  • 2020-12-11 15:35

    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)]
    
    0 讨论(0)
提交回复
热议问题