HashMap to print out letter frequency in decimals?

Viewed 132

I have this code:

public String LetterFreq(String t) {
HashMap<Character,Double> map= new HashMap<Character, Double>();
for(int i=0;i< t.length();i++) {
    char c=  t.charAt(i);
    Double val = map.get(c);
    if(val!= null) {
        map.put(c,new Double(val +1));
    }
    else {
        map.put(c, 1.0);
    }
    
    
}
for (Entry<Character, Double> entry : map.entrySet()) {
System.out.println(entry.getKey() + ":" + (entry.getValue()/t.length()));
}

In this code it iterates through each letter of string I give and maps a count to the key incrementing if there is multiple letters. Also when printing the line it divides the number (the count) by the length of the entire string. the problem I'm getting is that when I type a text inside I expect an out put to look like this :

letter: decimalvalue
letter: decimalvalue

but I get this instead:

: decimal value
letter: decimavalue
letter:decimalvalue...

some variation where no matter what I have a blank space with no letter yet it gives a decimal value which I'm not understanding why?

Update:

I'm assuming this has to do with spaces in the string but when I enter a text all together like thisisjulz we can see here that letter s comes up 2/10 which should mean .2 but instead my code registers spaces in even ones I didn't put like as seen in the quoted example above and counts it as 1 character space. Is there any way I can implement a delimiter or something to make sure it only counts the characters that have values?

Updatev2: this is where i grab "string t" from and how this all goes together: alice takes the value i input into the console and sends it to eve and all the Eve function does is LetterFreq(tex);

 public void Alice() 
{
System.out.println("Would you like to encrpyt a message or quit?");
System.out.println("To Encrypt press enter 9.");
System.out.println("If you wish to quit enter 0.");
System.out.println("If you made a mistake and want to go back to the main menu press 7.");

Scanner q = new Scanner(System.in);
   
switch (q.nextInt()) 
{
    case 0:
    System.out.println ("Thank you and goodbye.");
    break;

    case 9:
    System.out.println ("Please enter text:");
 
    
    String tex ="";
    String line;
    while (in.hasNextLine()) {
        line = in.nextLine();
        if (line.isEmpty()) {
            break;
        }
        tex += line + "\n";
    }
  
       tex= Encryption(tex);
       System.out.println(tex+"\n");
       System.out.println("Would you like to simulate Bob Or Eve? ");
       System.out.println("Enter 5 for Bob, 6 For Eve");
         
       in.hasNextInt();
       if(in.nextInt()==5) {
           tex= tex.replaceAll(" ", "");
          Bob(tex); 
       }
       if (in.nextInt()==6) {
           tex= tex.replaceAll(" ", "");
           Eve(tex);
       }
       else {
      
       break;
       }
case 7:
        new Menu();

    default:
    System.err.println ( "Unrecognized option" );
    break;
}
2 Answers

Here's a fully-working example using a regular expression with replaceAll(...). Also, I updated your code to use containsKey(c) instead of getting and checking whether the value fetched is null. It's a bit more elegant.

package eu.webfarmr;

import java.util.HashMap;
import java.util.Map.Entry;

public class LetterFrequency {
    public static void main(String[] args) {
        letterFreq("Some Example 38 sdf %");
    }

    public static void letterFreq(String t) {
        t = t.replaceAll("[^a-zA-Z]", "");
        HashMap<Character, Double> map = new HashMap<Character, Double>();
        for (int i = 0; i < t.length(); i++) {
            char c = t.charAt(i);
            if (map.containsKey(c)) {
                Double d = map.get(c);
                d++;
                map.put(c, d);
            } else {
                map.put(c, 1.0);
            }
        }
        for (Entry<Character, Double> entry : map.entrySet()) {
            System.out.println(entry.getKey() + ":" + (entry.getValue() / t.length()));
        }
    }
}

There's actually a neat map function as of Java 8 which you can use to further condense your code: map.merge(c, 1.0, Double::sum);. See the snippet below. Essentially what it does is set 1 as the value if no value present, otherwise increment.

public static void letterFreq(String t) {
    t = t.replaceAll("[^a-zA-Z]", "");
    HashMap<Character, Double> map = new HashMap<Character, Double>();
    for (int i = 0; i < t.length(); i++) {
        char c = t.charAt(i);
        map.merge(c, 1.0, Double::sum);
    }
}

I'm not able to reproduce what you see. I copied your code and made a test:

public String LetterFreq(String t) {
    HashMap<Character, Double> map = new HashMap<Character, Double>();
    for (int i = 0; i < t.length(); i++) {
        char c = t.charAt(i);
        Double val = map.get(c);
        if (val != null) {
            map.put(c, new Double(val + 1));
        } else {
            map.put(c, 1.0);
        }


    }
    for (Map.Entry<Character, Double> entry : map.entrySet()) {
        System.out.println(entry.getKey() + ":" + (entry.getValue() / t.length()));
    }
    return t;
}
@Test public void testLetterFreq() {
    LetterFreq("thisisjulz");
}

I produces:

s:0.2
t:0.1
u:0.1
h:0.1
i:0.2
j:0.1
z:0.1
l:0.1

... which seems correct to me

Related