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
Related
I got a list of sentences. I split each sentences and filtered the unwanted words and puncuations. and then store them into
ArrayList<ArrayList<String>> sentence
then I used a hashMap to find the most common word. how could I modify the following hashmap code so I can also find the most common consecutive pairs of words.(N-grams for phrases)
HashMap<String, Integer> hashMap = new HashMap<>();
// Splitting the words of string
// and storing them in the array.
for(int i =0; i < sentence.size(); i++){
ArrayList<String> words = new ArrayList<String>(sentence.get(i));
for (String word : words) {
//Asking whether the HashMap contains the
//key or not. Will return null if not.
Integer integer = hashMap.get(word);
if (integer == null)
// Storing the word as key and its
// occurrence as value in the HashMap.
hashMap.put(word, 1);
else {
// Incrementing the value if the word
// is already present in the HashMap.
hashMap.put(word, integer + 1);
}
}
}
i dont know where to start. should i adjust the way i split or do i no split at all in the first place.
To find the most common consecutive pairs of words (N-grams for phrases), you can modify the above code by looping through the sentence arraylist and creating a new hashmap with the pairs of words as the keys and the number of times they appear as the values. Then, you can iterate through the new hashmap and find the pair of words with the highest value.
public static String getMostCommonNGram(ArrayList<ArrayList<String>> sentence) {
HashMap<String, Integer> nGramMap = new HashMap<>();
// loop through the sentences
for (ArrayList<String> words : sentence) {
// loop through the words and create pairs of words
for (int i = 0; i < words.size() - 1; i++) {
String nGram = words.get(i) + " " + words.get(i + 1);
// check if the n-gram already exists in the map
Integer count = nGramMap.get(nGram);
// if not, add it to the map with count = 1
if (count == null) {
nGramMap.put(nGram, 1);
} else {
// if yes, increment the count
nGramMap.put(nGram, count + 1);
}
}
}
// find the n-gram with the highest count
String mostCommonNGram = "";
int maxCount = 0;
for (String nGram : nGramMap.keySet()) {
int count = nGramMap.get(nGram);
if (count > maxCount) {
maxCount = count;
mostCommonNGram = nGram;
}
}
return mostCommonNGram;
}
Give a string: apple and apple
Longest substring: again
Longest substring size: 5
I can't find where the problem is if is my code wrong. the program wants us to find a string that is repeated two times
package as;
import java.util.Scanner;
public class askisii {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
String stA,stB = null;
int i,count=0,j,p1,p2;
System.out.println("Give a string:");
stA=scan.nextLine();
for(i=0;i<stA.length()-1;i++) {
for( j=i+1;j<stA.length()-1;j++) {
if((stA.charAt(i)==stA.charAt(j)) && (stA.charAt(i+1)==stA.charAt(j+1))) {
stB+=stA.charAt(i);
p1=i;
p2=j;
while(stA.charAt(p1+1)==stA.charAt(p2+1)) {
stB+=stA.charAt(p1+1);
p1++;
p2++;
count++;
}
i=stA.length();
j=stA.length();
}
}
}
System.out.println("Longest substring:" + stB);
System.out.println("Longest substring size:" + count);
scan.close();
}
}
In your while loop, you did not check whether or not the index had gone too far. Your while loop traveled to the end of the string and still tried to grab more characters when there weren't any to grab.
Switch your while loop to look like this. I think it will solve this problem.
while(p1 + 1 < stA.length() && p2 + 1 < stA.length() && stA.charAt(p1+1) == stA.charAt(p2+1)) {
A more simple way to find the words with maximum no. of occurrence and with maximum length/size
// yourString is the string that you enter.
// Split this string by whitespaces, gives you an array of all words
String[] words = yourString.split("\\s+");
// Put in the map word against its no. occurrence count in the string
Map<String, Integer> wordsCount = new HashMap<>();
for(String word : words) {
wordsCount.put(word, wordsCount.get(word) == null ? 1 : wordsCount.get(word) + 1);
}
// Get the max occurrence count value amongst all words
int maxOccurrenceCount = Collections.max(wordsCount.values());
int maxLength = 0;
List<Map.Entry<String, Integer>> maxOccurrenceWordEntries = new ArrayList<>();
// Separate out the word with max occurrence and find the max length amongst the words
// with max no. of occurrences
for(Map.Entry<String, Integer> wordEntry : wordsCount.entrySet()) {
Integer occurrenceCount = wordEntry.getValue();
if(maxOccurrenceCount == occurrenceCount && wordEntry.getKey().length() >= maxLength) {
maxOccurrenceWordEntries.add(wordEntry);
maxLength = wordEntry.getKey().length();
}
}
// Finally print the words from the max no. occurrences, those whose length matches the maxLength
for(Map.Entry<String, Integer> wordEntry : maxOccurrenceWordEntries) {
if(wordEntry.getKey().length() == maxLength) {
System.out.printf("Word : %s | Count : %d | Size : %d \n",
wordEntry.getKey(), wordEntry.getValue(), wordEntry.getKey().length());
}
}
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;
}
}
I have a slight problem with a programme im working on, I need to be able to look through an array in Java and find the number of different duplicates in that array, for example if the array have the values 4, 6, 4 I need to be able to display:
There are:
2 words of length 1 (4 characters)
1 word of length 2 (6 characters)
What I've currently got is -
public class wordLength {
public static void main(String[] args) {
String userInput1 = "Owen Bishop Java ";
String [] inputArray = userInput1.split(" ");
for (int i = 0; i < inputArray.length; i++) {
int length = inputArray[i].length();
int inputArray2 = length;
System.out.println(inputArray2);
}
}
}
This currently will split the string into an array whenever there is a space, and then find and print the length of each of the words in the array, I need to show the amount of words that are the same length.
I'm really new to Java and appreciate this is probably an incredibly easy problem but any help would be hugely appreciated, thanks.
Without writing the whole thing (or making use of 3rd party libraries - I note you're new to Java so let's not complicate things), I would consider the following.
Make use of a Map<Integer,Integer> which would store the number of words of a particular length. e.g. to populate:
Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
for (String word : words) {
Integer current = counts.get(word.length());
if (current == null) {
current = 0;
}
current++;
counts.put(word.length(), current);
}
and then iterate through that to output the number of words per word count. Note that the above makes use of boxing.
The advantage of using a Map is that (unlike your array) you don't need to worry about empty counts (e.g. you won't have an entry if you have no words of length 5). That may/may not be an issue depending on your use case.
You can create an int array of length 20(or the maximum word length in English) and increase the index value before you print that value.
arr[length]++;
public class wordLength {
public static void main(String[] args) {
String userInput1 = "Owen Bishop Java ";
String [] inputArray = userInput1.split(" ");
Map<Integer,Integer> wordLengths = new HashMap<Integer,Integer>();
for (int i = 0; i < inputArray.length; i++) {
int length = inputArray[i].length();
if (wordLengths.containsKey(length))
wordLengths.put(length, wordLengths.get(length) + 1);
else
wordLengths.put(length, 1);
}
for (Integer length : new TreeSet<Integer>(wordLengths.keySet()))
System.out.println("Length: " + length + " Count: " + wordLengths.get(length));
}
}
}
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class wordLength {
public static void main(String[] args) {
String userInput1 = "Owen Bishop Java ";
String [] inputArray = userInput1.split(" ");
HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
for (int i = 0; i < inputArray.length; i++) {
int length = inputArray[i].length();
if(map.get(length)==null){
map.put(length, 1);
}
else map.put(length, map.get(length)+1);
}
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
System.out.println("words of length " +pairs.getKey() + " are " + pairs.getValue());
}
}
}
The output will be:
words of length 4 are 2
words of length 6 are 1
The beginning of your code looks good. What you basically want to keep track of (in my understanding) is a mapping from String length to the number of times this occurred.
public class wordLength {
public static void main(String[] args) {
String userInput1 = "Owen Bishop Java ";
String [] inputArray = userInput1.split(" ");
Map<Integer, Integer> counter = new HashMap<>(); //please note that I use the 'diamond' notation here, this is for Java 1.7 and higher.
for (int i = 0; i < inputArray.length; i++) {
int length = inputArray[i].length();
Integer num = counter.get(length);
if (num == null) {
num = 1;
}
else {
num++;
}
counter.put(length, num);
//or counter.put(length, num == null ? 1 : num++); instead of the if-else
}
//print the results
for (Entry<Integer, Integer> entry : map.entrySet()) {
System.out.println("There are " + entry.getValue() + " words with length " + entry.getKey() + ".");
}
}
}
The previous submitted method of arr[length]++; does work, but uses way to many space. Say you have only words of length 20 and beyond, then the first 20 elements of this arr are useless...
Please also note that you can use the map.entrySet() method from the Map interface. It is a better coding practice to use this method than using map.keySet() and after that looking up the associated value. This saves you much look up time. (especially with large user inputs!!!)
I have 2 solutions for above problem
Using extra space i.e. Map to store unique value. Complexity O(n) + Space(N) [N= #unique value]
No extra space. Sorts the input and counts values. Complexity nLog(n) + n
First Solution
Create a map to store each unique value as key and its count as value
Iterate over input array
If value exists as key then increment counter
ELSE if value does exist in map, then put value and set counter as 1
private static void UniqueValueUsingMap(int[] a){
//Map with
// key: unique values
// Value: count as each value (key)
Map<Integer, Integer> store = new HashMap<Integer, Integer>();
for (int i : a) {
Integer key = Integer.valueOf(i);
Integer count = null;
if(store.containsKey(key)){
count = store.get(key);
}else{
count = 0;
}
count++;
store.put(key, count);
}
}
Second solution
Sort the given Array nlog(n). All same values will be together after sort.
Iterate over sorted array
Maintain 2 variable i.e. previous value and counter for current value
When value change, print the value/count and reset the counter
Note: : int defaults to 0 inital value. Need to add additional check for it.
private static void CountValueUsingSort(int[] a){
//Sort the input array
Arrays.sort(a);
int currentValue = 0;
int counter =0;
for (int curr : a) {
if(curr != currentValue){
System.out.println("Value: " + currentValue + " Count:" + counter);
//Reset counter
counter = 0;
}
currentValue = curr;
//increment Count
counter++;
}
}
I want to go through a map with integer keys that are in the range of 14000-18000. I want to go through them and print the relative difference between them. So if there were three keys 14152 and 14153, 14159, the print output would be 0, 1, 7.
I have put my keys and values into a TreeMap, since it stores things in order.
However, with my implementation:
int dayCounter = 0;
for (Entry<Integer, String> entry : map.entrySet())
{
builder.append(dayCounter);
dayCounter = entry.getKey();
}
I am going through the map but know no way of getting the "previous" entry. If I was using an array I could get the (i-1)th value and subtract from i to get the relative value. Is there any way to get thie functionality with java maps?
simplest and fastest way I think: you can store the last entry in a temp variable, and use it only on next iteration. Don't forget to modify it at the end of each iteration.
When you iterate, you know you have the smallest value first. So I would do something like this:
Integer first = null;
for(Integer i : map.keySet()) {
if(first == null) first = i; // save the first value
builder.append(i - first);
}
Using your example:
import java.util.TreeMap;
class Eggonlegs {
public static void main(String[] args) {
TreeMap<Integer,String> map = new TreeMap<Integer,String>();
map.put(14152,"First");
map.put(14153,"Second");
map.put(14159,"Third");
Integer first = null;
for(Integer i : map.keySet()) {
if(first == null) first = i; // save the first value
System.out.println(i - first);
}
}
}
Results in
c:\files>javac Eggonlegs.java
c:\files>java Eggonlegs
0
1
7
c:\files>
Now, it's possible that's not what you intended. Perhaps you want the difference between each node, which not what your example shows. In that case, I would leverage the Collections library like this:
List<Integer> list = new ArrayList<Integer>(map.keySet());
for(int i = 0; i < list.size(); i++) {
if(i == 0) builder.append(0);
else builder.append(list.get(i) - list.get(i-1));
}
Here's an example of that, incase it's what oyu actually intended:
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
class Eggonlegs {
public static void main(String[] args) {
TreeMap<Integer,String> map = new TreeMap<Integer,String>();
map.put(14152,"First");
map.put(14153,"Second");
map.put(14159,"Third");
List<Integer> list = new ArrayList<Integer>(map.keySet());
for(int i = 0; i < list.size(); i++) {
if(i == 0) System.out.println(0);
else System.out.println(list.get(i) - list.get(i-1));
}
}
}
Results in
c:\files>javac Eggonlegs.java
c:\files>java Eggonlegs
0
1
6
c:\files>
Why don't you hold it in a separate variable?
//Warning : Notepad coding.
int hold_prev_key = -1;
for(int key : map.keySet())
{
if(hold_prev_key != -1)
builder.append(key - hold_prev_key);
hold_prev_key = key;
}
I didn't explain my question well. Sorry guys. I wanted a cumulative running total. This is what I did by combining your answers:
int hold_previous_key = 0;
int difference = 0;
int running_total = 0;
for (int key : map.keySet())
{
if (hold_previous_key != 0)
{
difference = key - hold_previous_key;
running_total += difference;
builder.append(key + " - " + hold_previous_key + " = " + difference + " RUNNING TOTAL = " + running_total + "; ");
}
else
{
// print 0 for the first date in the data set
builder.append("first val = 0" + "; ");
}
hold_previous_key = key;
}