Counting letter occurrences in words [duplicate] - java

This question already has answers here:
count specific characters in a string (Java)
(8 answers)
Closed 7 years ago.
I'm attempting to make my program in java count the number of letters in each word. Right now I have it counting words, not letters. Any help to get it to do letters would be great!
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import java.util.Scanner;
public class LetterTypeCount
{
public static void main(String[] args) {
// create HashMap to store String keys and Integer values
Map<String, Integer> myMap = new HashMap<>();
createMap(myMap); // create map based on user input
displayMap(myMap); // display map content
}
// create map from user input
private static void createMap(Map<String, Integer> map)
{
Scanner scanner = new Scanner(System.in); // create scanner
System.out.println("Enter a string:"); // prompt for user input
String input = scanner.nextLine();
// tokenize the input
String[] tokens = input.split(" ");
// processing input text
for (String token : tokens)
{
String letter = token.toLowerCase(); // get lowercase letter
// if the map contains the letter
if (map.containsKey(letter)) // is letter in map
{
int count = map.get(letter); // get current count
map.put(letter, count + 1); // increment count
}
else
map.put(letter, 1); // add new letter with a count of 1 to map
}
}
// display map content
private static void displayMap(Map<String, Integer> map)
{
Set<String> keys = map.keySet(); // get keys
// sort keys
TreeSet<String> sortedKeys = new TreeSet<>(keys);
System.out.printf("%nMap contains:%nKey\t\tValue%n");
// generate output for each key in map
for (String key : sortedKeys)
System.out.printf("%-10s%10s%n", key, map.get(key));
System.out.printf("%nsize: %d%nisEmpty: %b%n",
map.size(), map.isEmpty());
}
} // end class LetterTypeCount
I'm thinking I need to use the String charAt method somewhere

Might not be very elegant but:
public class LetterTypeCount
{
public static void main(String[] args) {
// create HashMap to store String keys and Integer values
Map<String, Integer> myMap = new HashMap<>();
createMap(myMap); // create map based on user input
displayMap(myMap); // display map content
}
// create map from user input
private static void createMap(Map<String, Integer> map)
{
Scanner scanner = new Scanner(System.in); // create scanner
System.out.println("Enter a string:"); // prompt for user input
String input = scanner.nextLine();
// split to words
String[] words = input.split(" ");
for (String word : words)
{
word = word.toLowerCase(); // get lowercase word
for(int i=0; i<word.length(); i++)
{
char c = word.charAt(i); //get char at position i
if (map.containsKey(c + "")) // is letter in map
{
int count = map.get(c + ""); // get current count
map.put(c + "", count + 1); // increment count
}
else
map.put(c + "", 1); // add new letter with a count of 1 to map
}
// if the map contains the letter
}
}
// display map content
private static void displayMap(Map<String, Integer> map)
{
Set<String> keys = map.keySet(); // get keys
// sort keys
TreeSet<String> sortedKeys = new TreeSet<>(keys);
System.out.printf("%nMap contains:%nKey\t\tValue%n");
// generate output for each key in map
for (String key : sortedKeys)
System.out.printf("%-10s%10s%n", key, map.get(key));
System.out.printf("%nsize: %d%nisEmpty: %b%n",
map.size(), map.isEmpty());
}
} // end class LetterTypeCount

You could create a for loop and add +1 for each letter to an array or a HashMapcontaining the letter occurance.
for(int i=0; i<= input.length(); i++){
mymap.put(input.charAt(i), myMap.get(input.charAt(i)+1));
}
But then you should define your variable myMap global and not inside your main method.

Supposing that you count latin chars only:
public int[] letters = new int['z' - 'a' + 1];
// count chars:
for (String token : tokens)
for (char c : token.toLowerCase().toCharArray())
if (c >= 'a' && c <= 'z')
letters[c - 'a']++;
// then print out counts:
for (int i = 0; i < 'z' - 'a' + 1; i++)
if (letters[i] > 0)
System.out.format("%s occurs %s time(s)\n", (char)('a' + i), letters[i]);
This looks a bit "low-level", but this is working Java code (just tested!), which uses interchangeability of chars and ints on arithmetical operations.

You can try Java 8 Stream API
Besides Java streams you also should know Java Lambda Expressions
String input = "ANY String";
Map<String, Long> map = Arrays.stream(input.split("")) // Stream String
.map(String::toLowerCase) // All letters to lower case
.filter(letter -> !letter.equals(" ")) // Remove spaces
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

You can simply use str.length() like so:
System.out.println(key.length());

Related

Assign unique int values to a word in a String then store it into an Array

I'm trying to get the unique words within a string then storing it within an array along with the amount of times it occurs.
My approach towards this was to assign a unique integer to each unique string within an if-else statement, then taking the unique counts of those integers, and pulling any one word from the string that's assigned a unique value, and finally taking the number of times the unique integer occurs.
However, whenever I get to assigning a unique value to the String I get null:
import java.util.Arrays;
public class StringLearning {
public static void main(String[] args) {
final String text = "Win Win Win Win Draw Draw Loss Loss";
int[] numbers = null;
if(text.equals("Win")) {
numbers= new int[1];
}else if(text.equals("Draw")){
numbers = new int [2];
}else if(text.equals("Loss")) {
numbers = new int [3];
}
System.out.println(Arrays.toString(numbers));
}
}
Expected output:
{1, 1, 1, 1, 2, 2, 3, 3}
EDIT:
How could this be implemented in a general sense? Such that, I did not know the String had "Win, Loss, Draw" in the string, but I'd want to assign a unique integer to any given unique word?
you have many problems with your code.
first, you have to get each word of the string individual, so you need to split it into array.
second, you need to create one array, and in it to put the integers. (what you did is to create new array for each number)
I tried to fix the problems. hope you understand my code.
(I only fixed your code, and not make it generial)
String[] arr = text.split(" ");
int[] numbers = new int[arr.length];
for (int i=0;i<arr.length;i++){
if(arr[i].equals("Win")) {
numbers[i] = 1;
}else if(arr[i].equals("Draw")){
numbers[i] = 2;
}else if(arr[i].equals("Loss")) {
numbers[i] = 3;
}
}
When creating an object of an array, the number in the brackets new int[1] you declare the length of the array. I'd recommend using a HashMap for that matter. An example of code would be:
public class StringLearning {
public static void main(String[] args) {
final String text = "Win Win Win Win Draw Draw Loss Loss";
HashMap<String, Integer> counts = new HashMap<String, Integer>();
for (String word : text.split(" ")) { // loops through each word of the string
// text.split(" ") returns an array, with all the parts of the string between your regexes
// if current word is not already in the map, add it to the map.
if (!counts.containsKey(word)) counts.put(word, 0);
counts.put(word, counts.get(word) + 1); // adds one to the count of the current word
}
// lambda expression
counts.forEach((string, integer) -> System.out.printf("amount of \"%s\": %d\n", string, integer));
}
}
Output:
amount of "Draw": 2
amount of "Loss": 2
amount of "Win": 4
Edit (response to tQuadrat):
I edited this post to keep everything clean and readable.
public class StringLearning {
public static void main(String[] args) {
final String text = "Win Win Win Win Draw Draw Loss Loss";
HashMap<String, Integer> counts = new HashMap<String, Integer>();
for (String word : text.split(" ")) { // loops through each word of the string
// text.split(" ") returns an array, with all the parts of the string between your regexes
// if current word is not already in the map, add it to the map.
if (!counts.containsKey(word))
counts.put(word, counts.size() + 1); // index of the word (+ 1 because your expected output was 1-indexed)
}
for (String word : text.split(" ")) {
System.out.print(counts.get(word) + " ");
}
}
}
Output:
1 1 1 1 2 2 3 3
Let's try this approach:
Get the number of words in the String: var words = text.split( " " ); This assumes that words are separated by blanks only.
Create registry for the words: Map<String,Integer> registry = new HashMap<>();
Create the result array: var result = new int [words.length];
Now loop over the words and check if you have seen the word already:
for( var i = 0; i < words.length; ++i )
{
result [i] = registry.computeIfAbsent( words [i], $ -> registry.size() + 1 );
}
Finally, print the result: System.out.println( Arrays.toString( result ) ); – although this would use […] instead of {…}.
registry.computeIfAbsent( words [i], $ -> registry.size() + 1 ); adds a new entry to the registry for each unseen word and assigns the size of the registry plus one as the unique number for that word. For already known words, it returns the previously assigned number.
This works for any set of words in text.
So the complete thing may look like this:
public final class StringLearning
{
public static final void main( final String... args )
{
final var text = "Win Win Win Win Draw Draw Loss Loss"; // … or any other text
final var words = text.split( " " );
final Map<String,Integer> registry = new HashMap<>();
final var result = new int [words.length];
for( var i = 0; i < words.length; ++i )
{
result [i] = registry.computeIfAbsent( words [i], $ -> registry.size() + 1 );
}
System.out.println( Arrays.toString( result ) );
}
}
Maintain the unique value for each word of string in map and then fetch the unique value while assigning your array.
String text = "Win Win Loss Draw Hello";
String[] split = text.split(" ");
// To maintain unique value for each word of input string
Map<String, Integer> = new HashMap<>();
int counter = 0;
for(String ele:split)
if(!map.containsKey(ele))
map.put(ele, ++counter)
// Getting unique value for each word and assigining in array
int[] array=new int[split.length];
for(int i=0; i<split.length;i++)
array[i] = map.get(split[i]);

Creating a HashMap of chars in a string and integers in an ArrayList<integer>

I have to create a HashMap that records the letters in a string and their index values in a ArrayList, so that if the HashMap is called with some string key, each related index integer is returned, and so that the map can be called by itself such that each key is shown with their indexes, For example for the string "Hello World", the map would look something like:
d=[9], o=[4, 6], r=[7], W=[5], H=[0], l=[2, 3, 8], e=[1].
I'm really confused by the requirement of the inputs as String and ArrayList, rather than chars and integers. Could you explain to me the relationship of the map to those objects, and to their components which are ultimately what are recorded as keys and values? When trying to debug, it stops processing before the map call.
The error message is:
java.lang.AssertionError: Wrong number of entries in Concordance. Expected: 5. Got: 1
Expected :1
Actual :5
But I really think I'm not grasping HashMap very well, so I'd appreciate if anyone could guide me through the basics, or provide anything educational about using HashMap, especially ones that use ArrayList.
public HashMap<String, ArrayList<Integer>> concordanceForString(String s) {
HashMap<String, ArrayList<Integer>> sMap = new HashMap<>();//create map "sMap"
char[] sArray = new char[s.length()]; //create character array, "sArray", for string conversion
ArrayList<Integer> sCharIndex = new ArrayList<Integer>();
for (int i = 0; i < s.length(); i++) {
sArray[i] = s.charAt(i); // convert string into array
}
for (int j = 0; j < sArray.length; j++){
sCharIndex.add(j); // add char indexes to index ArrayList
}
sMap.put(s, sCharIndex); //add the String and ArrayList
return sMap; // I feel like this should be sMap.get(s) but when I do, it gives me the zigzag red underline.
}
Here is a way to do it:
String input = "hello world";
Map<String, List<Integer>> letters = new HashMap<String, List<Integer>>();
// remove all whitespace characters - since it appears you are doing that
String string = input.replaceAll("\\s", "");
// loop over the length of the string
for (int i = 0; i < string.length(); i++) {
// add the entry to the map
// if it does not exist, then a new List with value of i is added
// if the key does exist, then the new List of i is added to the
// existing List
letters.merge(string.substring(i, i + 1),
Arrays.asList(i),
(o, n) -> Stream.concat(o.stream(), n.stream()).collect(Collectors.toList()));
}
System.out.println(letters);
that gives this output:
{r=[7], d=[9], e=[1], w=[5], h=[0], l=[2, 3, 8], o=[4, 6]}
EDIT - this uses a Character as the key to the map:
String input = "hello world";
Map<Character, List<Integer>> letters = new HashMap<Character, List<Integer>>();
String string = input.replaceAll("\\s", "");
for (int i = 0; i < string.length(); i++) {
letters.merge(string.charAt(i), Arrays.asList(i), (o, n) ->
Stream.concat(o.stream(), n.stream()).collect(Collectors.toList()));
}
System.out.println(letters);
Essentially, this is what you want to do.
This presumes a HashMap<String, List<Integer>>
List<Integer> sCharIndex;
for (int i = 0; i < s.length(); i++) {
// get the character
char ch = s.charAt(i);
if (!Character.isLetter(ch)) {
// only check letters
continue;
}
ch = ch+""; // to string
// get the list for character
sCharIndex = sMap.get(ch);
// if it is null, create one and add it
if (sCharIndex == null) {
// create list
sCharIndex = new ArrayList<>();
// put list in map
sMap.put(ch, sCharIndex);
}
// at this point you have the list so
// add the index to it.
sCharIndex.add(i);
}
return sMap;
A hashMap is nothing more than a special data structure that takes an object as a key. Think of an array that takes a digit as an index and you can store anything there.
A hashMap can take anything as a key (like an index but it is called a key) and it can also store anything.
Note that your key to hashMap is a String but you're using a character which is not the same. So you need to decide which you want.
HashMap<String, List<Integer>> or HashMap<Character, List<Integer>>
There are also easier ways to do this but this is how most would accomplish this prior to Java 8.
Here is a much more compact way using streams. No loops required.
Map<String, List<Integer>> map2 = IntStream
.range(0,s.length())
// only look for letters.
.filter(i->Character.isLetter(s.charAt(i)))
.boxed()
// stream the Integers from 0 to length
// and group them by character in a list of indices.
.collect(Collectors.groupingBy(i->s.charAt(i)+""));
But I recommend you become familiar with the basics before delving into streams (or until your instructor recommends to do so).
For more information check out The Java Tutorials
Check out this code :
public static void main(String []args){
//Create map of respective keys and values
HashMap<Character, ArrayList<Integer>> map = new HashMap();
String str = "Hello world"; //test string
int length = str.length(); //length of string
for(int i = 0; i < length; i++){
ArrayList<Integer> indexes = new ArrayList(); //empty list of indexes
//character of test string at particular position
Character ch = str.charAt(i);
//if key is already present in the map, then add the previous index associated with the character to the indexes list
if(map.containsKey(ch)){
//adding previous indexes to the list
indexes.addAll(map.get(ch));
}
//add the current index of the character to the respective key in map
indexes.add(i);
//put the indexes in the map and map it to the current character
map.put(ch, indexes);
}
//print the indexes of 'l' character
System.out.print(map.get('l'));
}
The code is self explanatory.
public class Array {
public static void main(String[] args) {
printSortedMap(concordanceForString("Hello world")); // r[7] d[9] e[1] w[5] H[0] l[2, 3, 8] o[4, 6]
}
public static HashMap<String, ArrayList<Integer>> concordanceForString(String s) {
HashMap<String, ArrayList<Integer>> sMap = new HashMap<>();
String str = s.replace(" ", "");
for (int i = 0; i < str.length(); i++) {
ArrayList<Integer> sCharIndex = new ArrayList<Integer>();
for (int j = 0; j < str.length(); j++) {
if ( str.charAt(i) == str.charAt(j) ) {
sCharIndex.add(j);
}
}
sMap.put(str.substring(i,i+1), sCharIndex);
}
return sMap;
}
public static void printSortedMap(HashMap<String, ArrayList<Integer>> sMap) {
for (Map.Entry<String, ArrayList<Integer>> entry : sMap.entrySet()) {
System.out.println(entry.getKey() + entry.getValue());
}
}

How to hold position of every character from encoded string

I am trying to hold the position of every character (A-Z) from encoded string. I am unable to find out a way to implement it in Java.
Below is one example from C++ which I am trying to rewrite in Java.
map<Character,Integer> enc = new map<Character,Integer>();
for (int i = 0; i < encoded.length(); i++)
{
enc[encoded.charAt(i)] = i;
}
Example below:
I will have a Keyword which is unique e.g., Keyword is NEW.
String will be formed by concatenating KEYWORD+Alphabets(A-Z which are not in the Keyword) e.g., NEWABCDFGHIJKLMOPQRSTUVXYZ (note that N,E and W are not repeated again in the above in the 26-Character string. Finally, I would like to hold the position of every character i.e., A-Z from the above string in bold.
If I'm understanding what youre saying, you want to map each character in a string to its index. However, Maps need a unique key for each entry, so your code wont work directly for strings which contain duplicate characters. Instead of using an Integer for each character, we'll use a List of Integers to store all the indexes which this character appears.
Here's how you would do that in java:
public static void main(String[] args) {
Map<Character, List<Integer>> charMap = new HashMap<>();
String string = "aaabbcdefg";
for (int i = 0; i < string.length(); i++) {
Character c = string.charAt(i);
if (charMap.containsKey(c)) {
List<Integer> positions = charMap.get(c);
positions.add(i);
} else {
charMap.put(c, new ArrayList<>(Arrays.asList(i)));
}
}
for (Character c : charMap.keySet()) {
System.out.print(c + ": ");
charMap.get(c).forEach(System.out::print);
System.out.println();
}
}
output:
a: 012
b: 34
c: 5
d: 6
e: 7
f: 8
g: 9
If you don't want to handle duplicates letters , you can do as follows, it’ll only keep last occurrence for each letter :
Map<Character, Integer> enc = new HashMap<>();
for (int i = 0; i < encoded.length(); i++) {
enc.put(encoded.charAt(i), i);
}
——————-
To handle duplicates char, you can hold them in a List or concatenate them in a String for example (on the second I add a filter operation to remove spaces)
public static void main (String[] args)
{
String str = "AUBU CUDU";
Map<Character, List<Integer>> mapList =
IntStream.range(0, str.length())
.boxed()
.collect(Collectors.toMap(i->str.charAt(i), i->Arrays.asList(i), (la,lb)->{List<Integer>res =new ArrayList<>(la); res.addAll(lb); return res;}));
System.out.println(mapList);
//{ =[4], A=[0], B=[2], C=[5], D=[7], U=[1, 3, 6, 8]}
Map<Character, String> mapString =
IntStream.range(0, str.length())
.boxed()
.filter(i->(""+str.charAt(i)).matches("[\\S]"))
.collect(Collectors.toMap(i->str.charAt(i), i->Integer.toString(i), (sa,sb)-> sa+sb ));
System.out.println(mapString);
//{A=0, B=2, C=5, D=7, U=1368}
}
Code Demo

Display occurrence of each letter in a string?

public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.println("type the sentence you want to find the letters of");
String sentence = s.nextLine();
getLetters(sentence);
}
public static void getLetters(String sentence) {
int count;
char ch[] = sentence.toCharArray();
for (int i = 0; i < sentence.length(); i++) {
System.out.print(ch[i]);
}
}
I am trying to display the occurrence of each letter (letter only) in a sentence, and I am lost. I have converted the string into a char array, but I am now lost.
For instance, if I typed the sentence: "Hello, how are you?"
The result would be:
Occurrence of h: 1
Occurrence of e: 2
Occurrence of l: 2
Occurrence of o: 3
etc..
I know I need to utilize my int count, but I am not sure how to do that. Our professor is having us use this:
c[26];
c[ch - 'a']++;
And I'm not sure where to use those for this little project.
Edit: Update
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.println("type the sentence you want to find the letters of");
String sentence = s.nextLine();
getLetters(sentence);
}
public static void getLetters(String sentence) {
sentence = sentence.toLowerCase();
int count[];
char ch[] = sentence.toCharArray();
for (int i = 0; i < sentence.length(); i++) {
System.out.print(ch[i]);
}
char alphabet[] = "abcdefghijklmnopqrstuvwxyz".toCharArray();
System.out.println();
}
}
Use a HashMap<Character, Integer> to keep track. The key is a unique character, and the integer counts the number of times you see it.
import java.util.HashMap;
public class J {
public static void main(String[] args) {
String string = "aaaabbbccd";
HashMap<Character, Integer> map = frequency(string);
System.out.println(map);
}
public static HashMap<Character, Integer> frequency(String string) {
int length = string.length();
char c;
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
// loop thru string
for (int i = 0; i < length; i++) {
c = string.charAt(i);
// If u have already seen that character,
// Increment its count
if (map.containsKey(c)) {
map.put(c, map.get(c) + 1);
// otherwise this is the first time u
// have seen it, so set count to 1
} else {
map.put(c, 1);
}
}
return map;
}
}
Output:
{a=4, b=3, c=2, d=1}
I don't see reason to use HashMap here. HashMaps are used to map some values into places in memory for faster access, using HashFunction. In this case he will have same, or very similar thing with array and this mapping function that is given to him(ch-'a') . Also, for someone who is doing this, it is maybe too soon for HashMap.
Your problem is that you haven't understood idea.
Letters in java have values (You can check ASCII table). You have 26 letters in alphabet, first one is 'a' and last is 'z'. So you want to have array of 26 elements. Every time when you have 'a' into your string, you want to increment element in place 0 in array, when you come into 'b' you want to increment element in place 1.... when you come to 'z' element 25. So, in fact with (ch-'a') you map your letter in place in array where is count of its ocurrence.
You take string, do .toLowerCase() case on it, pass it once to count letters, then print what you found.

Take user input, put into an array and print out how many times each letter is used

I am trying to write this program so that when the user inputs a line of text they are given a chart showing how many times each letter is used. I broke it up into an array but I kept getting an error for "counts[letters[a] == 'a']++;" saying i can't convert a string to a char or a boolean to a int, depending on the way I put it. I can't figure out why it's not all char.
import java.util.*;
public class AnalysisA { //open class
public static String input;
public static String stringA;
public static void main (String args []) { //open main
System.out.println("Please enter a line of text for analysis:");
Scanner sc = new Scanner(System.in);
input = sc.nextLine();
input = input.toLowerCase();
System.out.println("Analysis A:");//Analysis A
System.out.println(AnalysisA(stringA));
} // close main
public static String AnalysisA (String stringA) { // open analysis A
stringA = input;
char[] letters = stringA.toCharArray();
int[] counts = new int[26];
for (int a = 0; a < letters.length; a++) { //open for
counts[letters[a] == 'a']++;
System.out.print(counts);
} //close for
}
counts[___] expect an Integer index, whereas your expression letters[a] == 'a' return a boolean
Im guessing you're trying to increment your 'Dictionary' value by 1 each time a letter is met.
You can get the index by making letters[a] - 'a'
Because of the order in the ASCII table, letter 'a' which equal 97 if subtracted to another letter, say 'b' which is 98, will produce the index 1, which is the correct position for your base26 'Dictionary'
Extra:
You should use for (int i = ... for indexing (i instead of a, its easy to mixed variables up if you name your index like that)
You must make
sure all the characters are lower-case before you start doing this,
because as you can see in the table above 'B' - 'a' and 'b' - 'a'
are 2 very different things.
The expression letters[a] == 'a' results in a boolean answer (1 or 0), but you have that indexing an array, which must be an int.
What you're basically telling Java is to do counts[true]++ or counts[false]++, which makes no sense.
What you really want is a HashMap that maps each character to the amount of times you saw it in the array. I won't put the answer here, but look up HashMaps in Java and you'll find the clues you need.
If you use a Map you can do this easily without complicating..
Map<Character, Integer> map = new HashMap<Character, Integer>();
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
public class AnalysisA { // open class
public static String input;
public static void main(String args[]) { // open main
System.out.println("Please enter a line of text for analysis:");
Scanner sc = new Scanner(System.in);
input = sc.nextLine();
input = input.toLowerCase();
sc.close();
System.out.println("Analysis A:");// Analysis A
System.out.println(Analysis());
} // close main
public static String Analysis() { // open analysis A
Map<Character, Integer> map = new HashMap<Character, Integer>();
char[] letters = input.toCharArray();
Integer count;
for (char letter : letters) {
count = map.get(letter);
if (count == null || count == 0) {
map.put(letter, 1);
} else {
map.put(letter, ++count);
}
}
Set<Character> set = map.keySet();
for (Character letter : set) {
System.out.println(letter + " " + map.get(letter));
}
return "";
}
}

Categories