counting occurance of characters using hashtable in Java - java

I am trying to count occurrence of each character in a string.
So if I input aaabbbccc I am expecting o/p as {a=3, b=3, c=3} but instead I keep on getting it as {a=1, b=1, c=1} as my hashtable contains method fails and returns false. What is wrong in the code?
I also know that there is a HashMap collection quite similar to hashtable. but as I am learing java I want to try the same code with all datastructures just to get an idea of methods. The code with map is not much different than what I am doing here still this code fails. and I am not able to figure out where is the bug in the code.
I have following code:
Hashtable<Character, Integer> stringHash = new Hashtable<Character, Integer>();
This stringHash is a class level variable.
for(int i=0; i<s.length(); i++){
if(stringHash ==null || stringHash.size()==0){
stringHash.put(s.charAt(i), 1);
}
else{
if(! stringHash.contains(s.charAt(i)) ){
System.out.println(s.charAt(i));
stringHash.put(s.charAt(i), 1);
}
else{
int count = stringHash.get(s.charAt(i));
stringHash.put(s.charAt(i), count++);
}
}
System.out.println(stringHash + " " + s.charAt(i) + " "+ stringHash.contains(s.charAt(i)));
}

This code works for me:
String s = "aaabbbccc";
Map<Character, Integer> stringHash = new HashMap<Character, Integer>();
for (char ch : s.toCharArray())
stringHash.put(ch, stringHash.containsKey(ch) ? (stringHash.get(ch) + 1) : 1);
System.out.println(stringHash);
// output: "{a=3, b=3, c=3}"
I am using a Map<K, V> instead of HashTable<K, V>, but this is more common.

Try something like this....The reason your code is failing is that you are checking contains() on HashTable instead of its keySet. Hope that helps
public static void main(String[] args) {
// TODO Auto-generated method stub
String s = "aaaaabbcccc";
Hashtable<Character, Integer> counter = new Hashtable<Character, Integer>();
int count = 0;
for(int i=0;i<s.length();i++){
if(!counter.keySet().contains(s.charAt(i))){
counter.put(s.charAt(i), 1);
} else {
count = counter.get(s.charAt(i));
counter.put(s.charAt(i), ++count);
}
}
for(char c:counter.keySet()) {
System.out.println("Character : "+c+" - Occurences : "+counter.get(c));
}
}
o/p
Character : b - Occurences : 2
Character : c - Occurences : 4
Character : a - Occurences : 5

Your code
if(stringHash ==null || stringHash.size()==0){
stringHash.put(s.charAt(i), 1);
}
would throw NPE if somehow the hashmap is null. Luckily it seems that you have initialized it properly. The block rather should have been
if(stringHash ==null){
stringHash = new HashMap()
stringHash.put(s.charAt(i), 1);
}
Again, that would not have fixed your bug. You should use containsKey instead of contains that checks for value in HashTable. What you are looking to implement can be summarized in following pseudocode.
initialize hashmap
for each character c in inputString
count = 0
if hashmap has a key for c
count = get value for c from hashmap
end if
put in to hashmap c, count + 1
end for
In Java this would look like :
Map<Character, Integer> charCountMap = new HashMap<>();
for(char c : inputString.toCharArray()){
int count = 0;
if(charCountMap.containsKey(c)){
count = charCountMap.get(c);
}
charCountMap.put(c,count+1);
}
Or for the adventurous, here is Java8 version
Map<Character,Long> map = s.chars().mapToObj(i->(char)i)
.collect(Collectors
.groupingBy(e -> e,
Collectors.counting()));
System.out.println(map);
Finally, do not use HashTable its a legacy class, no one uses it now a days. Stick with HashMap or other flavors of Map implementations.

Debug my code questions are discouraged, but in the way of solving the general problem of counting characters in a string I can suggest a much simpler method:
public static int[] countCharacters( String s ){
int[] count = new int[ 256 ];
for( int xChar = 0; xChar < s.length(); xChar++ ) count[ s.charAt( xChar ) ]++;
return count;
}
This assumes you have single byte characters.

Why do you use hashMap for counting character occurance?
I would use integer array of size 255 like so:
int[] counter = new int[256];
String s = "aaabbbcccc";
for(int i = 0; i < s.length(); i++){
counter[s.charAt(i)]++;
}
for(int i = 0; i < counter.length; i++)
if(counter[i] > 0)
System.out.println(((char)i) + " occurs " + counter[i] + " times");
that coude would give an output:
a occurs 3 times
b occurs 3 times
c occurs 4 times

Don't use Hashtable, you can simplify that code a lot, something like this should work:
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
public class Main {
public static void main(String[] args) {
Map<Character, Long> countMap = count("aabbbcccc");
for (Map.Entry<Character, Long> entry : countMap.entrySet()) {
System.out
.println(MessageFormat.format("Char ''{0}'' with count ''{1}''", entry.getKey(), entry.getValue()));
}
}
private static Map<Character, Long> count(String value) {
Map<Character, Long> countMap = new HashMap<Character, Long>();
if (StringUtils.isNotBlank(value)) {
for (int i = 0; i < value.length(); i++) {
Long count = countMap.get(value.charAt(i));
count = count == null ? 1 : count + 1;
countMap.put(value.charAt(i), count);
}
}
return countMap;
}
}

Related

Trying to count occurence of each letter in String in Java

I am not able to get the correct occurrence of each letter present in the string. What is wrong with my code?
Code:
public class consecutiveCharacters {
public static String solve(String A, int B) {
HashMap<String, Integer> map = new HashMap<>();
for (int i=0;i<A.length();i++) {
Integer value = map.get(A.charAt(i));
if(value == null){
map.put(String.valueOf(A.charAt(i)),1);
}
else {
map.put(String.valueOf(A.charAt(i)),i+1);
}
}
System.out.println(map);
String text = "i feel good";
return text;
}
public static void main(String[] args) {
solve("aabbccd",2);
}
}
The output of the map should be:
{a=2, b=2, c=2, d=1}
Yet the output that the above code is giving is:
{a=1, b=1, c=1, d=1}
Using Map.merge() you can rid of checking this yourself:
Map<Character, Integer> map = new HashMap<>();
for( char c : A.toCharArray()) {
map.merge(c, 1, Integer::sum);
}
merge() takes 3 parameters:
A key which is the character in your case
A value to put for the key, which is 1 in your case
A merge bi-function to combine the new and existing values if the entry already existed. Integer::sum refers to Integer's method static int sum(int a, int b) which basically is the same as your value + 1.
I would use the following logic:
public static void solve(String A) {
Map<Character, Integer> map = new HashMap<>();
for (int i=0; i < A.length(); i++) {
char letter = A.charAt(i);
int count = map.get(letter) != null ? map.get(letter) : 0;
map.put(letter, ++count);
}
System.out.println(map); // prints {a=2, b=2, c=2, d=1}
}
public static void main(String[] args) {
solve("aabbccd");
}
The main changes I made were to switch to using a Map<Character, Integer>, since we want to keep track of character key counts, rather than strings. In addition, I tightened the lookup logic to set the initial count at either zero, in case a new letter comes along, or the previous value in the map, in case the letter be already known.
A more generic solution is to use Map<Character, Integer>:
public static void solve(String str) {
Map<Character, Integer> map = new HashMap<>();
for(int i = 0; i < str.length(); i++) {
char ch = Character.toLowerCase(str.charAt(i));
map.merge(ch, 1, Integer::sum);
}
System.out.println(map);
}
In case you have only English letter, then solution could be more memory effective:
public static void solve(String str) {
str = str.toLowerCase();
int[] letters = new int[26];
for (int i = 0; i < str.length(); i++)
letters[str.charAt(i) - 'a']++;
for (int i = 0; i < letters.length; i++)
if (letters[i] > 0)
System.out.format("%c=%d\n", 'a' + i, letters[i]);
}
The problem seems to be in this line map.put(String.valueOf(A.charAt(i)),i+1) where it is resetting the count every time it found a recurrence of a character. You need to get the previous count of a character if it recurred. Try changing the line to map.put(String.valueOf(A.charAt(i)),map.get(String.valueOf(A.charAt(i)))+1).
Also you can use Character directly as the key in your HashMap object, which will make the code much simpler. Hope the following code will be helpful:
public static String solve(String A, int B) {
HashMap<Character, Integer> count = new HashMap<>();
for(Character ch: A.toCharArray()){
if(count.containsKey(ch) == false){
count.put(ch, 0);
}
count.put(ch, count.get(ch)+1);
}
System.out.println(count);
String text = "i feel good";
return text;
}
// A = "aabbccd"
// count = {a=2, b=2, c=2, d=1}
The reason why it is not working is that you are putting a key of type String and you are trying to get using a character value.
The fastest way to solve the bug would be to change the get to
map.get(String.valueOf(A.charAt(i)))
Another way to do a check if a key does not exist is to use the contains method.
map.containsKey(String.valueOf(A.charAt(i)))

find matching characters in two strings at different indexes

I am a C++ programmer. Out of interest, I am developing a java application.
I have two strings in java:
String word1 = "Fold";
String word2 = "Flow";
Now I need a function to get the count of matching characters in both strings but those that are at different indexes. The strings could be of any length but always both words will be of the same length.
Added:
We should increment count for a character by that many occurrences in both words. Ex: abcd and xyaa should return 1, but abca and xaay should return 2. Hope it is clear now.
For ex:, the count for the above example should be 2 (Only letters 'o' and 'l' are considered. Though letter 'f' is present in both words, it is not considered since it is present at the same index on both strings.
My method was to create two map variables Map and initialize it with 0 for all characters. Then calculate count of how many times each letter occurs in both strings and finally check how many of these characters have count more than one.
Ex:
Map<Character, Integer> word_count_1 = createMap(); // initialize with a:0, b:0, c:0,...z:0
Map<Character, Integer> word_count_2 = createMap(); // initialize with a:0, b:0, c:0,...z:0
int count, value;
for (int i=0; i<word1.length(); i++)
{
if (word1.charAt(i) != word2.charAt(i))
{
value = word_count_1.get(word1.charAt(i));
word_count_1.put(word1.charAt(i), ++value);
value= word_count_2.get(word2.charAt(i));
word_count_2.put(word2.charAt(i), ++value);
}
}
Set set = word_count_2.entrySet();
Iterator i = set.iterator();
Map.Entry<Character, Integer> iter;
while(i.hasNext())
{
iter = (Map.Entry)i.next();
if ( (iter.getValue() > 0) && (word_count_1.get(iter.getKey())) > 0 )
{
count++; // This line has a bug. We shall ignore it for now
}
}
Is there any other better method to get the count instead of what I am trying to do? I just dont get a good feeling about what I have done.
Edited:
The line count++ (that I mentioned having a bug) should be changed to following to give correct result:
int letterCount1 = word_count_1.get(iter.getKey());
int letterCount2 = iter.getValue();
if ( (letterCount1 > 0) && (letterCount2 > 0 )
{
int minVal = letterCount1;
if (minVal > letterCount2)
minVal = letterCount2;
count+= minVal;
}
Java 8 Solution
public int duplicates(String wordOne, String wordTwo ){
Set<Character> charSet = new HashSet(109);
wordOne.chars().mapToObj(i -> (char)i).forEach(letter->charSet.add(letter));
int count = 0;
for(int i = 0; i < wordTwo.length(); i++)
if( charSet.contains(wordTwo.charAt(i)) && wordTwo.charAt(i) != wordOne.charAt(i) )
count++;
return count;
}
duplicates("Fold", "Flow"); // -> 2
There's nicer syntax to iterate over the set (see example below) but the actual counting looks fine.
Map<Character, Integer> word_count_1 = createMap(); // initialize with a:0, b:0, c:0,...z:0
Map<Character, Integer> word_count_2 = createMap(); // initialize with a:0, b:0, c:0,...z:0<Character, Integer>
int count, value;
for (int i=0; i<word1.length(); i++)
{
if (word1.charAt(i) != word2.charAt(i))
{
value = word_count_1.get(word1.charAt(i));
word_count_1.put(word1.charAt(i), ++value);
value= word_count_2.get(word2.charAt(i));
word_count_2.put(word2.charAt(i), ++value);
}
}
Set set = word_count_2.entrySet();
for(<Map.Entry<Character, Integer>> iter:set)
{
if ( (iter.getValue() > 0) && (word_count_1.get(iter.getKey())) > 0 )
{
count++; // This line has a bug. We shall ignore it for now
}
}
//Create set which contains word1's unique chars
Set<Character> word1Chars = new HashSet<>();
for(int i = 0; i< word1.length(); i++)
{
char ch = word1.charAt(i);
word1Chars.add(ch);
}
// Count how many chars in word2 are contained in word1 but in another position
int count = 0;
for(int i = 0; i < word2.length(); i++)
{
char ch = word2.charAt(i);
if(ch != word1.charAt(i) && word1Chars.contains(ch))
{
count++;
}
}
EDIT: You have to take into consideration that you may get a different counting depending on which word you iterate. E.g: "abc" and "daa"; "abc" has 1 but "daa" has 2.
If you want the total of correspondences in both words you need to modify this code accordingly.
You do not need to initialize maps for all the characters.
public static int matchCharCountInDifferentIndex(String word1, String word2) {
Map<Character, Integer> word_count_1 = new HashMap<>();
Map<Character, Integer> word_count_2 = new HashMap<>();
for (int i=0; i<word1.length(); i++)
{
if (word1.charAt(i) != word2.charAt(i))
{
word_count_1.compute(word1.charAt(i), (k, v) -> v == null ? 1 : v + 1);
word_count_2.compute(word2.charAt(i), (k, v) -> v == null ? 1 : v + 1);
}
}
int count = 0;
for (Map.Entry<Character, Integer> e : word_count_2.entrySet())
{
count += Math.min(e.getValue(), word_count_1.getOrDefault(e.getKey(), 0));
}
System.out.printf("word1=%s word2=%s result=%d%n", word_count_1, word_count_2, count);
return count;
}
Tests are
matchCharCountInDifferentIndex("Fold", "Flow"); // -> word1={d=1, l=1, o=1} word2={w=1, l=1, o=1} result=2
matchCharCountInDifferentIndex("abca", "xaay"); // -> word1={a=2, b=1, c=1} word2={a=2, x=1, y=1} result=2
In this code
map.compute(key, (k, v) -> v == null ? 1 : v + 1);
is equivalent to
map.put(key, map.getOrDefault(key, 0) + 1);
And
map.getOrDefault(key, 0)
is equivalent to
map.containsKey(key) ? map.get(key) : 0;

Sort the words and letters in Java

The code below counts how many times the words and letters appeared in the string. How do I sort the output from highest to lowest? The output should be like:
the - 2
quick - 1
brown - 1
fox - 1
t - 2
h - 2
e - 2
b - 1
My code:
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
public class Tokenizer {
public static void main(String[] args) {
int index = 0;
int tokenCount;
int i = 0;
Map<String, Integer> wordCount = new HashMap<String, Integer>();
Map<Integer, Integer> letterCount = new HashMap<Integer, Integer>();
String message = "The Quick brown fox the";
StringTokenizer string = new StringTokenizer(message);
tokenCount = string.countTokens();
System.out.println("Number of tokens = " + tokenCount);
while (string.hasMoreTokens()) {
String word = string.nextToken().toLowerCase();
Integer count = wordCount.get(word);
Integer lettercount = letterCount.get(word);
if (count == null) {
// this means the word was encountered the first time
wordCount.put(word, 1);
} else {
// word was already encountered we need to increment the count
wordCount.put(word, count + 1);
}
}
for (String words : wordCount.keySet()) {
System.out.println("Word : " + words + " has count :" + wordCount.get(words));
}
for (i = 0; i < message.length(); i++) {
char c = message.charAt(i);
if (c != ' ') {
int value = letterCount.getOrDefault((int) c, 0);
letterCount.put((int) c, value + 1);
}
}
for (int key : letterCount.keySet()) {
System.out.println((char) key + ": " + letterCount.get(key));
}
}
}
You have a Map<String, Integer>; I'd suggest something along the lines of another LinkedHashMap<String, Integer> which is populated by inserting keys that are sorted by value.
It seems that you want to sort the Map by it's value (i.e., count). Here are some general solutions.
Specifically for your case, a simple solution might be:
Use a TreeSet<Integer> to save all possible values of counts in the HashMap.
Iterate the TreeSetfrom high to low.
Inside the iteration mentioned in 2., use a loop to output all word-count pairs with count equals to current iterated count.
Please see if this may help.
just use the concept of the list and add all your data into list and then use sort method for it

Find if a string is unique or not

I want to use hashtable to find unique characters as it seems more efficient to me so for example, hello in hashtable would be=> {h:1,e:1,l:2,o:1} & since value is more than 1 then string isnt unique. I know I can do ascii way of counting unique characters but I want to implement the hashtable way.
Please note, I do not want a regex implementation.
static void findHashUnique(String str)
{
Hashtable<Character, Integer> ht = new Hashtable<Character, Integer>();
for(int i=0;i<str.length();i++)
{
int cnt=1;
if(!ht.containsKey(str.charAt(i)))
{
ht.put(str.charAt(i), cnt);
}
}
System.out.print(ht);
}
I am stuck at the part of how will I first initialize the hashtable & also check if value exists then increment. In case of 'l' it will increment to 2 instead of being 1 since the key is the same.
Also Is this solution efficient?
Here's my approach.
String string = "hello";
Hashtable<Character, Integer> map = new Hashtable<>();
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
if (map.containsKey(c)) {
map.put(c, map.get(c) + 1);
} else {
map.put(c, 1);
}
}
System.out.println(map);
Output: {e=1, o=1, l=2, h=1}
Well, I don't know exactly what character encodings you will be examining, but if you are constraining yourself to only ASCII characters, you can use a simple array of 128 elements.
public static String uniqueLetters(String s) {
// storage for ascii characters
char[] letters = new char[128];
// mark counts of all letters
for(int i = 0; i < s.length(); i++) {
letters[ (int)s.charAt(i) ]++;
}
// find unique letters
String uniques = "";
for(int i = 0; i < letters.length; i++) {
if ( letters[i] == 1 ) {
uniques += Character.toString( (char)letters[i] );
}
}
return uniques;
}
To "fix" your code, use a HashSet<Character>, which uses a Hashtable internally, but you don't have to know or worry about that. Just keep adding the chars to the set and you'll be left with a unique set of chars at the end.
To achieve the intention more easily:
String uniqueChars = str.replaceAll("(.)(?=.*\\1)", "");

Sorting frequency of chars

I just made an algorithm that counts the frequency of chars in a String. What I am confused about is how to sort the frequency so the character with the greatest number of occurences is listed at the top, and the least at the bottom.
At first I tried having another variable 'fc' (for frequency counter) to coincide with my original counter variable 'k'. However I am stuck in the thought process of how to go about sorting this frequency, the fc var I made is just useless.
Thanks for any help provided!
Here is my code:
import java.io.*;
public class Freq
{
public static void main(String args[])throws IOException
{
//read input stream
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
int ci,i,j,k,l,fc;l=0;
String str,str1;
char c,ch;
System.out.println("Enter your String");
str=in.readLine();
i=str.length();
//cycle through ASCII table chars and obtain chars typed
for(c='A';c<='z';c++)
{
k=0;
fc=0; //fc keeps count like k
for(j=0;j<i;j++)
{
ch=str.charAt(j);
if(ch==c)
k++;
fc=k-1; //was going to represent this counter for 'less than k'
}
if(k>0)
System.out.println("The character "+c+" has occured for "+k+" times");
}
}
}
You will need to store them all first. You can use a HashMap to store them all, it will also simplify your counting routine. Then Collections.sort on the entry set. You will need to make a Comparable> to compare the entry values for sorting.
Edited to add sample code....
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter your String");
String line = in.readLine();
HashMap<Character,Integer> counts = new HashMap<>();
for(char c : line.toCharArray()) {
Integer count = counts.get(c);
if (count == null) {
count = 0;
}
counts.put(c, ++count);
}
List<Entry<Character,Integer>> list = new ArrayList<>(counts.entrySet());
Collections.sort(list, new Comparator<Entry<Character,Integer>>() {
#Override
public int compare(Entry<Character, Integer> o1,
Entry<Character, Integer> o2) {
return o2.getValue() - o1.getValue();
}
});
for(Entry<Character,Integer> entry : list) {
System.out.println("The character "+entry.getKey() +" has occured for "+ entry.getValue()+" times");
}
You can follow these steps:
1) Create a class call CharCount having two fields : char and freq. Override equals to return true if characters are equal and override hashcode to return character's hashcode. Make it implement Comparable and override compare and return -1,0 or 1 based on values of freq of objects being compared
2) Have a Set of CharCount
3)Each time you find a character create an instance of this class with character and freq as 0.
4)Check if it exists in set and update feq accordingly
5) Sort set data yourself or call Collections.sort
I would do it like this:
int[] frequencyArray = new int['z' -'A'];
String inputString = "ttttttttttttttttest";
for(int i = 0; i<inputString.length();i++)
{
frequencyArray[inputString.charAt(i) -'A']++;
}
Then, you can sort this array by any of the popular sorting algorithms of your choosing.
EDIT Made the code more memory efficient.
Make a function count that gives you the count of particular character and sort on behalf of count, e.g
if( count(str,str.charAt[j]) > count(str,str.charAt[j+1]) )
SWAP
its better to convert str to char array before this, then it will be like
count(chararr,charrarr[j])
This one works faster than Hashmap solution:
public static void frequencySort(String s) {
int[] f = new int[256];
for (int c : s.toCharArray())
f[c]++;
List<CharStore> list = new ArrayList<>();
for (int i = 0; i < f.length; i++) {
if (f[i] != 0) list.add(new CharStore(i, f[i]));
}
Collections.sort(list);
for (CharStore c : list) {
System.out.println(((char)c.c) + " has occured " + c.count + " times";
}
}
static class CharStore implements Comparable<CharStore> {
int c;
int count;
public CharStore(int c, int count) {
this.c = c;
this.count = count;
}
#Override
public int compareTo(CharStore o) {
return o.count - count;
}
}

Categories

Resources