Get all characters from a string with their number - java

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);
}
}

Related

Compare Certain Strings (part of sentence) from Paragraph

I have a Map,
HashMap<String,String> dataCheck= new HashMap<String,String>();
dataCheck.put("Flag1","Additional Income");
dataCheck.put("Flag2","Be your own boss");
dataCheck.put("Flag3","Compete for your business");
and a paragraph.
String paragraph = "When you have an additional Income, you can be your
own boss. So advertise with us and compete for your business. We help
you get additional income";
So what I want to achieve is for every member of the Hashmap, I want to compare it with the paragraph and find a number of repetitions. The match My output must be as follows:
Flag1 - 2 , Flag2 - 1 , Flag3 - 1
So, basically, I just want to get an idea on how I compare certain string with another set of strings.
Update: The Match would be case insensitive.
You can use a loop with String.indexOf() to count occurrences.
In the following code, you'll see we are looping through our HashMap and comparing each entry to our paragraph.
HashMap<String, String> dataCheck = new HashMap<String, String>();
dataCheck.put("Flag1", "Additional Income");
dataCheck.put("Flag2", "Be your own boss");
dataCheck.put("Flag3", "Compete for your business");
String paragraph = "When you have an additional Income, you can be your own boss. So advertise with us and compete for your business. We help you get additional income";
// Now, iterate through each entry in the Map
for (Map.Entry<String, String> entry : dataCheck.entrySet()) {
// Keep track of the number of occurrences
int count = 0;
// After finding a match, we need to increase our index in the loop so it moves on to the next match
int startingIndex = 0;
// This will convert the strings to upper case (so our matches are case insensitive
// It will continue looping until we get an an indexOf == -1 (which means no match was found)
while ((startingIndex = paragraph.toUpperCase().indexOf(entry.getValue().toUpperCase(), startingIndex)) != -1) {
// Add to our count
count++;
// Move our index position forward for the next loop
startingIndex++;
}
// Finally, print out the total count per Flag
System.out.println(entry.getKey() + ": " + count);
}
Here is the result:
Flag1: 2
Flag2: 1
Flag3: 1

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...

Java String manipulation based on most frequent char count

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

How can I use a string array as key in hash map?

I've made an String array out of a .txt and now want to make a HashMap with this string as key. But I don't want to have the String as one key to one value, I want to have each Information as a new key for the HashMap.
private static String[] readAndConvertInputFile() {
String str = StdIn.readAll();
String conv = str.replaceAll("\'s", "").replaceAll("[;,?.:*/\\-_()\"\'\n]", " ").replaceAll(" {2,}", " ").toLowerCase();
return conv.split(" "); }
So the information in the string is like ("word", "thing", "etc.", "pp.", "thing").
My value should be the frequency of the word in the text. So for example key: "word" value: 1, key: "thing" value: 2 and so on... I'm clueless and would be grateful if someone could help me, at least with the key. :)
You can create a Map while using the String value at each array index as the key, and an Integer as the value to keep track of how many times a word appeared.
Map<String,Integer> map = new HashMap<String,Integer>();
Then when you want to increment, you can check if the Map already contains the key, if it does, increase it by 1, otherwise, set it to 1.
if (occurences.containsKey(word)) {
occurences.put(word, occurences.get(word) + 1);
} else {
occurences.put(word, 1);
}
So, while you are looping over your string array, convert the String to lower case (if you want to ignore case for word occurrences), and increment the map using the if statement above.
for (String word : words) {
word = word.toLowerCase(); // remove if you want case sensitivity
if (occurences.containsKey(word)) {
occurences.put(word, occurences.get(word) + 1);
} else {
occurences.put(word, 1);
}
}
A full example is shown below. I converted to words to lowercase to ignore case when using the key in the map, if you want to keep case, remove the line where I convert it to lowercase.
public static void main(String[] args) {
String s = "This this the has dog cat fish the cat horse";
String[] words = s.split(" ");
Map<String, Integer> occurences = new HashMap<String, Integer>();
for (String word : words) {
word = word.toLowerCase(); // remove if you want case sensitivity
if (occurences.containsKey(word)) {
occurences.put(word, occurences.get(word) + 1);
} else {
occurences.put(word, 1);
}
}
for(Entry<String,Integer> en : occurences.entrySet()){
System.out.println("Word \"" + en.getKey() + "\" appeared " + en.getValue() + " times.");
}
}
Which will give me output:
Word "cat" appeared 2 times.
Word "fish" appeared 1 times.
Word "horse" appeared 1 times.
Word "the" appeared 2 times.
Word "dog" appeared 1 times.
Word "this" appeared 2 times.
Word "has" appeared 1 times.
Yes, you can use an array (regardless of element type) as a HashMap key.
No, shouldn't do so. The behavior is unlikely to be what you want (in general).
In your particular case, I don't see why you even propose using an array as a key in the first place. You seem to want Strings drawn from among your array elements as keys.
You could construct a word frequency table like so:
Map<String, Integer> computeFrequencies(String[] words) {
Map<String, Integer> frequencies = new HashMap<String, Integer>();
for (String word: words) {
Integer wordFrequency = frequencies.get(word);
frequencies.put(word,
(wordFrequency == null) ? 1 : (wordFrequency + 1));
}
return frequencies;
}
In java 8 using stream
String[] array=new String[]{"a","b","c","a"};
Map<String,Integer> map1=Arrays.stream(array).collect(Collectors.toMap(x->x,x->1,(key,value)->value+1));

Count occurrences of each unique character

How to find the number of occurrence of every unique character in a String? You can use at most one loop. please post your solution, thanks.
Since this sounds like a homework problem, let's try to go over how to solve this problem by hand. Once we do that, let's see how we can try to implement that in code.
What needs to be done?
Let's take the following string:
it is nice and sunny today.
In order to get a count of how many times each character appears in the above string, we should:
Iterate over each character of the string
Keep a tally of how many times each character in the string appears
How would we actually try it?
Doing this this by hand might be like this:
First, we find a new characeter i, so we could note that in a table and say that i appeared 1 time so far:
'i' -> 1
Second, we find another new character t, so we could add that in the above table:
'i' -> 1
't' -> 1
Third, a space, and repeat again...
'i' -> 1
't' -> 1
' ' -> 1
Fourth, we encounter an i which happens to exist in the table already. So, we'll want to retrieve the existing count, and replace it with the existing count + 1:
'i' -> 2
't' -> 1
' ' -> 1
And so on.
How to translate into code?
Translating the above to code, we may write something like this:
For every character in the string
Check to see if the character has already been encountered
If no, then remember the new character and say we encountered it once
If yes, then take the number of times it has been encountered, and increment it by one
For the implementation, as others have mentioned, using a loop and a Map could achieve what is needed.
The loop (such as a for or while loop) could be used to iterate over the characters in the string.
The Map (such as a HashMap) could be used to keep track of how many times a character has appeared. In this case, the key would be the character and the value would be the count for how many times the character appears.
Good luck!
It's a homework, so cannot post the code, but here is one approach:
Iterate through the string, char by char.
Put the char in a hashmap key and initialize its value to 1 (count). Now, if the char is encountered again, update the value (count+1). Else add the new char to key and again set its value (count=1)
Here you go! I have done a rough program on Count occurrences of each unique character
public class CountUniqueChars{
public static void main(String args[]){
HashMap<Character, Integer> map;
ArrayList<HashMap<Character, Integer>> list = new ArrayList<HashMap<Character,Integer>>();
int i;
int x = 0;
Boolean fire = false;
String str = "Hello world";
str = str.replaceAll("\\s", "").toLowerCase();
System.out.println(str.length());
for(i=0; i<str.length() ; i++){
if(list.size() <= 0){
map = new HashMap<Character, Integer>();
map.put(str.charAt(i), 1);
list.add(map);
}else{
map = new HashMap<Character, Integer>();
map.put(str.charAt(i), 1);
fire = false;
for (HashMap<Character, Integer> t : list){
if(t.containsKey(str.charAt(i)) == map.containsKey(str.charAt(i))){
x = list.indexOf(t);
fire = true;
map.put(str.charAt(i), t.get(str.charAt(i))+1);
}
}
if(fire){
list.remove(x);
}
list.add(map);
}
}
System.out.println(list);
}
}

Categories