Java String manipulation based on most frequent char count - java

In recent interview, I was asked to find solution for below String manipulation program.
Given a string s, represent the most frequent character with 1, the 2nd most frequent character with 01, third with 001 etc.
if String is "marrymyyyr", then output should be :
char count for each character is m:2 , a:1, r:3, y:4 highest count
number is 4 so the character with that count should be printed 1
inplace of that char, char with count 3 should be printed as 01
inplace of that char and so on.
Output : 001(m)0001(a)01(r)01(r)1(y)001(m)1(y)1(y)1(y)01(r)
I used HashMap to keep track of count for each character. then I was unable to solve the problem. I know I have to implement some mechanism to apply hashing/mapping to hashmap based on most frequent char mapped with its correspondence resultant string with combination of"1" "0" and print char with mapped resultant string instead of that char.

You said you used HashMap. If you created the map as Map<Character, AtomicInteger>, then you can update the value directly, without affecting the map.
This improves performance of the counting step of the process, but also allows you to then replace the "count" value with a value representing the number of 0's to print for a character, aka a "rank".
Example: With the counts being m:2, a:1, r:3, y:4 (from question), you would sort the list descending (y:4, r:3, m:2, a:1), then replace the counts with incrementing ranks: y:0, r:1, m:2, a:3.
If you use a LinkedHashMap, then multiple characters with equal count would be ranked in order of first appearance.
With those ranks, you can now convert the input. (The following is for any Java version. On Java 8, lambdas would reduce the code a lot. I'll leave that as an exercise for you.)
private static String test(String input) {
char[] chars = input.toCharArray();
// Collect chars with count of occurrences
Map<Character, AtomicInteger> charMap = new LinkedHashMap<>();
for (Character c : chars) {
AtomicInteger count = charMap.get(c);
if (count == null)
charMap.put(c, new AtomicInteger(1));
else
count.incrementAndGet();
}
// Sort char/count pairs by count (descending)
#SuppressWarnings("unchecked")
Entry<Character, AtomicInteger>[] charArr = charMap.entrySet().toArray(new Map.Entry[charMap.size()]);
Arrays.sort(charArr, new Comparator<Entry<Character, AtomicInteger>>() {
#Override
public int compare(Entry<Character, AtomicInteger> e1, Entry<Character, AtomicInteger> e2) {
return Integer.compare(e2.getValue().intValue(), e1.getValue().intValue()); // descending
}
});
// Replace "count" with "rank" (this updates values in charMap)
for (int i = 0; i < charArr.length; i++)
charArr[i].getValue().set(i);
// Generate result
StringBuilder buf = new StringBuilder();
for (Character c : chars) {
int rank = charMap.get(c).intValue();
while (rank-- > 0)
buf.append('0');
buf.append('1');
buf.append('(').append(c).append(')'); // Remove?
}
return buf.toString();
}
Test
System.out.println(test("marrymyyyr"));
Output
001(m)0001(a)01(r)01(r)1(y)001(m)1(y)1(y)1(y)01(r)
The phrasing of the question makes it sound like the letters should be replaced ("inplace of"). If so, comment out or delete the line marked with // Remove?
Output
00100010101100111101

Related

How to validate input against a randomly generated set of letters. Also, how to institute a rounds system

I'm working on an assignment (very much a beginners assignment)and am looking for some guidance as opposed to the code necessarily although obviously code is extremely helpful.
The assignment is essentially a version of Boggle with preset words (i.e. you're given random letters, you need to make a word, word must come from a short preset list or else you get zero). I have no idea where to start when validating the inputted word to ensure it only uses the randomly generated letters with no duplicates unless there are multiples of the same letter in the set. Here's the code for the random letter generator
Random r = new Random();
char[] real = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
for(int i=0; i < letters.length; i++) {
letters[i] = real[r.nextInt(26)];
}
The game also has a rounds system predicated on the user asking for another round at the completion of the first one. What kind of loop should I use for this. Am extremely used to for loops so that's what I went for but I'm feeling I'm probably wrong here. The rounds are identical so obviously I'd just like to loop over the pre-existing code. This is how I've written the round code so far, want to know what I should be insitituting now before going to deep into a mistake
letters= Instantiable.getLetters(); //Retrieving encryption
JOptionPane.showMessageDialog(null, "Your random letters will be displayed" );
System.out.println(random);
//Input
JOptionPane.showMessageDialog(null, "please enter a word" );
1Answer = JOptionPane.showInputDialog("Player 1, your answer");
if (p1Answer.matches("^[a-zA-Z]*$")) {
System.out.println("Player 1's answer is :" + p1Answer);
}
else {
JOptionPane.showMessageDialog(null, "Your answer contains invalid characters.NO SOUP FOR YOU!" );
}
2Answer = JOptionPane.showInputDialog("Player 2, your answer");
if (p2Answer.matches("^[a-zA-Z]*$")) {
System.out.println("Player 2's answer is :" + p2Answer);
}
else {
JOptionPane.showMessageDialog(null, "Your answer contains invalid characters.NO SOUP FOR YOU!" );
}
}
}
I'm assuming I'm making a mistake by not slapping this into a do while loop, but honestly extremely unsure because I've mostly been coasting using for loops and thus, at this stage am extremely worried that if I choose the wrong loop at the outset I'll be stuck.
Any help would be very much appreciated. Happy New Year!
Use for loop to iterate over a collection of items or predefined set of values.
use while loop to check some condition and proceed for next iteration
do-while loop if condition check after executing some statements.
or recursion, if that simplifies your iteration logic(also note the performance).
There are a couple of different approaches to checking the letters. The first one that came to my mind was to store the letter allowance in a Map<Character, Integer> with the letters selected as keys and how many of each as value (no need to keep those with zero allowance).
Another approach is to have an int[] array matching the letters and store the allowance in there. Initialize all positions to 0 and then just increase them as letters are selected, letterAllowance[i]++;
Since your letter set is basically the lower case alphabet a-z you can even use the ascii value to determine the position in the array.
In both cases, you'd go through the word given by the user and count the number of letters, then checking if they match the allowance.
As mentioned, a do-while (or plain while) loop is a good choice for iteration.
Edit - Elaboration and Code samples
A Map<K, V> is a data structure which maps Keys to Values. It has the great property that lookup is in constant time, O(1). Below I will show how I thought it could be used for this application.
First though, the array solution. The premise here is that the alphabet is just a list of 26 possible values, possibly with repetitions. We can track the randomly selected characters by their position in the alphabet in an array with length 26. Each position in the array represents a letter (0 is a, 1 is b, etc.). The int value in that position shows how many of that letter the user is allowed to use.
final int charCount = 10;
Random r = new Random();
int[] allowedLettersArray = new int[26];
for (int i = 0; i < charCount; ++i) {
allowedLettersArray[r.nextInt(26)]++; // 26 characters in the alphabet. Array is initialized with 0 in every position. Increase the position with 1
}
When the user has entered a word, we check if he picked characters that were allowed. Here I'm using a map to collect the letters in the word, counting how many of each letter was used. We then iterate over the entries in the Map and check the letter count for each letter we found (Key in the Map) against our array of allowed letters. If there were more than allowed, the word is invalid. If we don't encounter any issue, the word is valid.
private static boolean checkWithArray(int[] allowedLetters, String userWord) {
// Collect user word characters to map.
// Map key is the each letter. Map value is how many of that letter we found in the word
Map<Integer, Long> userLetters = userWord.chars().boxed().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
boolean wordIsValid = true;
for (Map.Entry<Integer, Long> e : userLetters.entrySet()) {
if (e.getValue() > allowedLetters[e.getKey() - 97]) {
return false;
}
}
return true;
}
Note that we have to subtract 97 (the Ascii value of the character 'a') from the entry key to get the correct position.
Calling the method:
wordIsValid = checkWithArray(allowedLettersArray, userWord);
Map solution
Here is a solution with Map. In principle it works the same way as above but we use a Map<Character, Long> to track the allowed letters instead of an array.
Select allowed letters:
final int charCount = 10;
Random r = new Random();
List<Character> list = new ArrayList<>();
for (int i = 0; i < charCount; ++i) {
list.add((char) (r.nextInt(26) + 97));
}
// Collect to Map. Count how many of each is allowed.
// Map key is each character that is allowed. Map value is how many of that character is allowed (since there may be duplicates)
Map<Character, Long> allowedLettersMap = list.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
Checking method:
private static boolean checkWithMap(Map<Character, Long> allowedLetters, String userWord) {
// Collect word characters, same as above
Map<Character, Long> userLetters = userWord.chars().boxed().map(i -> (char) i.intValue()).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
boolean wordIsValid = true;
for (Map.Entry<Character, Long> e : userLetters.entrySet()) {
Long allowed = allowedLetters.get(e.getKey());
if (allowed == null) {
return false; // Word was not allowed. Contained character that was not allowed at all
}
if (e.getValue() > allowed) {
return false; // Word was not allowed. Contains more of a character than is allowed
}
}
return true; // No rules violations encountered, word is ok!
}
Edit #2 - Code simplified and put in a class
To put the code in a bit more context I separated it into a class. I also simplified the code to not use any Streams and only have 1 Collection, a List for the letters. It hopefully makes the code easier to read and understand.
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class ArrayLetterRandomizer {
private final int[] allowedLetters;
public ArrayLetterRandomizer(int letterCount) {
this.allowedLetters = new int[26];
Random r = new Random();
for (int i = 0; i < letterCount; ++i) {
allowedLetters[r.nextInt(26)]++; // 26 characters in the alphabet. Array is initialized with 0 in every position. Increase the position with 1
}
}
public boolean checkWord(String word) {
int[] wordComposition = new int[26]; // Letters a-z count
for (char c : word.toCharArray()) {
if (++wordComposition[c - 97] > allowedLetters[c - 97]) { // Increment letter count and check count is still within allowance
return false;
}
}
return true;
}
public List<Character> getLetters() {
List<Character> letters = new ArrayList<>();
for (int i = 0; i < 26; ++i) {
if (allowedLetters[i] != 0) {
for (int j = 0; j < allowedLetters[i]; ++j) {
letters.add((char) (i + 97));
}
}
}
return letters;
}
}
Use of the class (or interface if you want) should be easy enough to integrate into your code.
// Randomize 10 letters
ArrayLetterRandomizer randomizer = new ArrayLetterRandomizer(10);
// ...
if(!randomizer.checkWord(p1Answer)) {
System.out.println("Player 1 entered an invalid word. NO PIZZA FOR YOU!");
}

Counting Common Elements in a String Array

I am trying to make a program to count common elements occuring in all the Strings in a String[] array. I have the following:-
A master array and a flag array both of size 26
Now for each string: I am marking frequency 1 for each character that appears in the string without incrementing in flag array.
Now I am adding the values of flag array to corresponding values of master array
my code looks like this
for(String str : arr)
{
for(char ch : str.toCharArray())
{
flag[ch - 97] = 1;
master[ch - 97] =master[ch -97] + flag[ch - 97];
}
}
My plan is to finally count elements in the master array that have value equal to input string array's length. This count will represent the count of characters that are common to all the strings
But my code has a flaw.
if a String has duplicate elements for example, 'ball' (with 2 ls). The corresponding value of the element in master array is getting incremented again.
Which makes its value larger than what I wanted.
So this is what I did.
for(String str : arr)
{
newstr = ""; //to keep track of each character in the string
for(char ch : str.toCharArray())
{
int counter = 0;
for(int i = 0; i < newstr.length();i++)
{
char ch2 = newstr.charAt(i);
if (ch == ch2 )
{
counter = counter + 1; //if duplicate
break;
}
}
if(counter == 1)
{
break;
}
flag[ch - 97] = 1;
master[ch - 97] =master[ch -97] + flag[ch - 97];
newstr = newstr + ch;
}
}
Is this the right approach? or could this code be more optimized?
IMHO - "The right approach" is one you fully understand and can refactor at will. There are generally always multiple ways to approach solving any programming problem. Personally, I would approach (what I think is) the problem you are trying to solve in a manner more ideomatic to Java.
For the entire array of strings you are going to examine, every character in the first string you examine is in every string examined so far, so every character in that first string would go into a Map<Character, Integer> i.e. charCountMap.put(aChar, 1) For the second string and every string thereafter: If a character in the string under examination is in the map's keySet, then increment the associated Integer (increment that key's associated value) charCountMap.get(aChar)++. After examining every character in every string, then the keys in the keyset that map to Integers with values that match the original string array's length are exactly the characters that were found in every string.
So far, this proposed solution doesn't solve the repeating character problem you describe above. To solve that part, I think you need to keep a separate list of unique characters "seen so far" in the "string under examination" (and empty the list for every new string). You would check the "seen so far" list first, and skip all further processing of that character if found in "seen so far", only characters not "seen so far" (in this string under examination) would be checked against the map's keyset. example code
There is also a recursive approach to programming a solution to this problem, but I'll leave that fruit hanging low...

How to find all permutations of a given word in a given text?

This is an interview question (phone screen): write a function (in Java) to find all permutations of a given word that appear in a given text. For example, for word abc and text abcxyaxbcayxycab the function should return abc, bca, cab.
I would answer this question as follows:
Obviously I can loop over all permutations of the given word and use a standard substring function. However it might be difficult (for me right now) to write code to generate all word permutations.
It is easier to loop over all text substrings of the word size, sort each substring and compare it with the "sorted" given word. I can code such a function immediately.
I can probably modify some substring search algorithm but I do not remember these algorithms now.
How would you answer this question?
This is probably not the most efficient solution algorithmically, but it is clean from a class design point of view. This solution takes the approach of comparing "sorted" given words.
We can say that a word is a permutation of another if it contains the same letters in the same number. This means that you can convert the word from a String to a Map<Character,Integer>. Such conversion will have complexity O(n) where n is the length of the String, assuming that insertions in your Map implementation cost O(1).
The Map will contain as keys all the characters found in the word and as values the frequencies of the characters.
Example. abbc is converted to [a->1, b->2, c->1]
bacb is converted to [a->1, b->2, c->1]
So if you have to know if two words are one the permutation of the other, you can convert them both into maps and then invoke Map.equals.
Then you have to iterate over the text string and apply the transformation to all the substrings of the same length of the words that you are looking for.
Improvement proposed by Inerdial
This approach can be improved by updating the Map in a "rolling" fashion.
I.e. if you're matching at index i=3 in the example haystack in the OP (the substring xya), the map will be [a->1, x->1, y->1]. When advancing in the haystack, decrement the character count for haystack[i], and increment the count for haystack[i+needle.length()].
(Dropping zeroes to make sure Map.equals() works, or just implementing a custom comparison.)
Improvement proposed by Max
What if we also introduce matchedCharactersCnt variable? At the beginning of the haystack it will be 0. Every time you change your map towards the desired value - you increment the variable. Every time you change it away from the desired value - you decrement the variable. Each iteration you check if the variable is equal to the length of needle. If it is - you've found a match. It would be faster than comparing the full map every time.
Pseudocode provided by Max:
needle = "abbc"
text = "abbcbbabbcaabbca"
needleSize = needle.length()
//Map of needle character counts
targetMap = [a->1, b->2, c->1]
matchedLength = 0
curMap = [a->0, b->0, c->0]
//Initial map initialization
for (int i=0;i<needle.length();i++) {
if (curMap.contains(haystack[i])) {
matchedLength++
curMap[haystack[i]]++
}
}
if (matchedLength == needleSize) {
System.out.println("Match found at: 0");
}
//Search itself
for (int i=0;i<haystack.length()-needle.length();i++) {
int targetValue1 = targetMap[haystack[i]]; //Reading from hashmap, O(1)
int curValue1 = curMap[haystack[i]]; //Another read
//If we are removing beneficial character
if (targetValue1 > 0 && curValue1 > 0 && curValue1 <= targetValue1) {
matchedLength--;
}
curMap[haystack[i]] = curValue1 + 1; //Write to hashmap, O(1)
int targetValue2 = targetMap[haystack[i+needle.length()]] //Read
int curValue2 = curMap[haystack[i+needle.length()]] //Read
//We are adding a beneficial character
if (targetValue2 > 0 && curValue2 < targetValue2) { //If we don't need this letter at all, the amount of matched letters decreases
matchedLength++;
}
curMap[haystack[i+needle.length()]] = curValue2 + 1; //Write
if (matchedLength == needleSize) {
System.out.println("Match found at: "+(i+1));
}
}
//Basically with 4 reads and 2 writes which are
//independent of the size of the needle,
//we get to the maximal possible performance: O(n)
To find a permutation of a string you can use number theory.
But you will have to know the 'theory' behind this algorithm in advance before you can answer the question using this algorithm.
There is a method where you can calculate a hash of a string using prime numbers.
Every permutation of the same string will give the same hash value. All other string combination which is not a permutation will give some other hash value.
The hash-value is calculated by c1 * p1 + c2 * p2 + ... + cn * pn
where ci is a unique value for the current char in the string and where pi is a unique prime number value for the ci char.
Here is the implementation.
public class Main {
static int[] primes = new int[] { 2, 3, 5, 7, 11, 13, 17,
19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103 };
public static void main(String[] args) {
final char[] text = "abcxaaabbbccyaxbcayaaaxycab"
.toCharArray();
char[] abc = new char[]{'a','b','c'};
int match = val(abc);
for (int i = 0; i < text.length - 2; i++) {
char[] _123 = new char[]{text[i],text[i+1],text[i+2]};
if(val(_123)==match){
System.out.println(new String(_123) );
}
}
}
static int p(char c) {
return primes[(int)c - (int)'a'];
}
static int val(char[] cs) {
return
p(cs[0])*(int)cs[0] + p(cs[1])*(int)cs[1] + p(cs[2])*(int)cs[2];
}
}
The output of this is:
abc
bca
cab
You should be able to do this in a single pass. Start by building a map that contains all the characters in the word you're searching for. So initially the map contains [a, b, c].
Now, go through the text one character at a time. The loop looks something like this, in pseudo-code.
found_string = "";
for each character in text
if character is in map
remove character from map
append character to found_string
if map is empty
output found_string
found_string = ""
add all characters back to map
end if
else
// not a permutation of the string you're searching for
refresh map with characters from found_string
found_string = ""
end if
end for
If you want unique occurrences, change the output step so that it adds the found strings to a map. That'll eliminate duplicates.
There's the issue of words that contain duplicated letters. If that's a problem, make the key the letter and the value a count. 'Removing' a character means decrementing its count in the map. If the count goes to 0, then the character is in effect removed from the map.
The algorithm as written won't find overlapping occurrences. That is, given the text abcba, it will only find abc. If you want to handle overlapping occurrences, you can modify the algorithm so that when it finds a match, it decrements the index by one minus the length of the found string.
That was a fun puzzle. Thanks.
This is what I would do - set up a flag array with one
element equal to 0 or 1 to indicate whether that character
in STR had been matched
Set the first result string RESULT to empty.
for each character C in TEXT:
Set an array X equal to the length of STR to all zeroes.
for each character S in STR:
If C is the JTH character in STR, and
X[J] == 0, then set X[J] <= 1 and add
C to RESULT.
If the length of RESULT is equal to STR,
add RESULT to a list of permutations
and set the elements of X[] to zeroes again.
If C is not any character J in STR having X[J]==0,
then set the elements of X[] to zeroes again.
The second approach seems very elegant to me and should be perfectly acceptable. I think it scales at O(M * N log N), where N is word length and M is text length.
I can come up with a somewhat more complex O(M) algorithm:
Count the occurrence of each character in the word
Do the same for the first N (i.e. length(word)) characters of the text
Subtract the two frequency vectors, yielding subFreq
Count the number of non-zeroes in subFreq, yielding numDiff
If numDiff equals zero, there is a match
Update subFreq and numDiff in constant time by updating for the first and after-last character in the text
Go to 5 until reaching the end of the text
EDIT: See that several similar answers have been posted. Most of this algorithm is equivalent to the rolling frequency counting suggested by others. My humble addition is also updating the number of differences in a rolling fashion, yielding an O(M+N) algorithm rather than an O(M*N) one.
EDIT2: Just saw that Max has basically suggested this in the comments, so brownie points to him.
This code should do the work:
import java.util.ArrayList;
import java.util.List;
public class Permutations {
public static void main(String[] args) {
final String word = "abc";
final String text = "abcxaaabbbccyaxbcayxycab";
List<Character> charsActuallyFound = new ArrayList<Character>();
StringBuilder match = new StringBuilder(3);
for (Character c : text.toCharArray()) {
if (word.contains(c.toString()) && !charsActuallyFound.contains(c)) {
charsActuallyFound.add(c);
match.append(c);
if (match.length()==word.length())
{
System.out.println(match);
match = new StringBuilder(3);
charsActuallyFound.clear();
}
} else {
match = new StringBuilder(3);
charsActuallyFound.clear();
}
}
}
}
The charsActuallyFound List is used to keep track of character already found in the loop. It is needed to avoid mathing "aaa" "bbb" "ccc" (added by me to the text you specified).
After further reflection, I think my code only work if the given word has no duplicate characters.
The code above correctly print
abc
bca
cab
but if you seaarch for the word "aaa", then nothing is printed, because each char can not be matched more than one time. Inspired from Jim Mischel answer, I edit my code, ending with this:
import java.util.ArrayList;
import java.util.List;
public class Permutations {
public static void main(String[] args) {
final String text = "abcxaaabbbccyaxbcayaaaxycab";
printMatches("aaa", text);
printMatches("abc", text);
}
private static void printMatches(String word, String text) {
System.out.println("matches for "+word +" in "+text+":");
StringBuilder match = new StringBuilder(3);
StringBuilder notYetFounds=new StringBuilder(word);
for (Character c : text.toCharArray()) {
int idx = notYetFounds.indexOf(c.toString());
if (idx!=-1) {
notYetFounds.replace(idx,idx+1,"");
match.append(c);
if (match.length()==word.length())
{
System.out.println(match);
match = new StringBuilder(3);
notYetFounds=new StringBuilder(word);
}
} else {
match = new StringBuilder(3);
notYetFounds=new StringBuilder(word);
}
}
System.out.println();
}
}
This give me following output:
matches for aaa in abcxaaabbbccyaxbcayaaaxycab:
aaa
aaa
matches for abc in abcxaaabbbccyaxbcayaaaxycab:
abc
bca
cab
Did some benchmark, the code above found 30815 matches of "abc" in a random string of 36M in just 4,5 seconds. As Jim already said, thanks for this puzzle...

Count of Each Alphabet using Array

I have a string as an input eg. Testerty. I want to find the count of each alphabet in the string. I have tried using a HashMap. But I want to implement this using array.
Can you please suggest some way.
You can use ASCII to assign the letters number values:
int[] letters = new int[128]; // There are 128 different possible characters.
for(int i = 0; i < input.length; i++) {
char current = input.charAt(i);
int index = Character.getNumericValue(char);
letters[index]++;
}
ArrayList<Character> ch = new ArrayList<Character>();
ArrayList<Integer> count = new ArrayList<Integer>();
someMethod(String input) {
for(char c : input.toCharArray()) {
if(ch.indexOf(c) != -1) {
i.set(ch.indexOf(c), i.get(ch.indexOf(c))+1);
} else {
ch.add(c);
i.add(1);
}
}
}
doing it with a Map is easier, where the letters are keys and the values are counts. Using an array is more tricky; you could assign each letter a number, and use that number as an index into the array, and store the counts in the array. So 'A' is 1, 'B' is 2, etc....The algorithm is
Get next letter of string.
Get the index for the letter.
Increment the value at that index in the array by 1.
Of course you need to do null checking and whatever.
Note that this is logically a Map. It's just when you use a Map, the Map does step 2 above for you.
You should use a collection implementing Multiset iunterface, i.e. HashMultiset (both taken from Google Guava library). Multiset is designed to hold counts for objects in collection:
Multiset<String> m = HashMultiset.create(Arrays.asList("a", "a", "b", "c", "b", "a"));
// m.toString() prints "a x 3, b x 2, c x 1"
// m.count() gives 6
One way could be, you first create an array, then traverse string using charAt(index) method ,match the current char against those in the array.If you find the match ,increment the value there,or add it as a new entry in the array.

Get all characters from a string with their number

How in Java can I get list of all characters appearing in string, with number of their appearances ? Let's say we have a string "I am really busy right now" so I should get :
i-2, a-2, r-2, m-1 and so on.
Just have a mapping of every character and their counts. You can get the character array of a String using String#toCharArray() and loop through it using the enhanced for loop. On every iteration, get the count from the mapping, set it if absent and then increment it with 1 and put back in map. Pretty straightforward.
Here's a basic kickoff example:
String string = "I am really busy right now";
Map<Character, Integer> characterCounts = new HashMap<Character, Integer>();
for (char character : string.toCharArray()) {
Integer characterCount = characterCounts.get(character);
if (characterCount == null) {
characterCount = 0;
}
characterCounts.put(character, characterCount + 1);
}
To learn more about maps, check the Sun tutorial on the subject.
You commented that it's "for a project", but it's however a typical homework question because it's pretty basic and covered in the first chapters of a decent Java book/tutorial. If you're new to Java, I suggest to get yourself through the Sun Trails Covering the Basics.
Is it homework? Without knowing it I'll assume a best-effort answer.
The logic behind your problem is to
go trought the list one character at time
count that character: since possible characters (excluding unicode) are just 256 you can have an array of 256 ints and count them there: in this way you won't need to search the correct counter but just increment the right index.
I'm not sure of your exact needs but it seems you want to count occurrences regardless of the case, maybe also ignore characters such as whitespace, etc. So you might want something like this:
String initial = "I am really busy right now";
String cleaned = initial.replaceAll("\\s", "") //remove all whitespace characters
.toLowerCase(); // lower all characters
Map<Character, Integer> map = new HashMap<Character, Integer>();
for (char character : cleaned.toCharArray()) {
Integer count = map.get(character);
count = (count!=null) ? count + 1 : 1;
map.put(character, count);
}
for (Map.Entry<Character, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
Tweak the regex to meet your exact requirements (to skip punctuation, etc).
String input = "AAZERTTYAATY";
char[] chars = input.toCharArray();
Map<Character, Integer> map = new HashMap<>();
for (char aChar : chars) {
Integer charCount = map.putIfAbsent(aChar, 1);
if (charCount != null) {
charCount++;
map.put(aChar, charCount);
}
}

Categories