I have a text file which has lines of animals, who occur on this list from 1 to n times. I need to read this text file, count all the separate animal occurences, sort them from highest to lowest and put them in a jtable.
For example, the text file looks like this:
dog
sheep
cat
horse
cat
tiger
cat
cat
tiger
I need to count all the same occurences like so:
dog 1
sheep 1
cat 4
horse 1
tiger 2
And then sort them from highest to lowest and somehow put them into a table, so that would be:
Animal name: count
cat 4
tiger 2
dog 1
sheep 1
horse 1
So, for now my specific question is how can i count the matches for all the separate animals?
Thanks for the help!
EDIT
The answer provided by Vishal Kamat, has worked, my animals and their occurences have been counted with this code:
java hashmap word count from a text file
Now, I just need to put all this information to a new jtable
Just use the switch-case. You can use a counter for each animal. Or use an arrayList where you can store the amount of each animal...
String line = reader.readLine();
while (line != null) {
switch (line) {
case "cat":
catCounter++;
break;
case "dog":
dogCounter++;
break;
case "horse":
horseCounter++;
break;
case "tiger":
tigerCounter++;
break;
case "sheep":
sheepCounter++;
break;
default:
break;
}
}
Unfortunately I'm not able to write and test a code, but I am able to give you a path to do the thing you want.
You can use Regex for matching how many times, let's say "cat" was mentioned in the text file.
Perhaps this would help: http://code.runnable.com/UqUJWzqM7L8-AAFT/how-to-count-the-number-of-matching-string-in-java-for-regex
I did not write the code, credits to Mirang.
You can have a Map<String, Integer> where key would be the animal name and count would be the occurances so far. Everytime you read an animal, get the value from the map and increment it. Finally you can sort the Map using the integer value of the count and store in the table.
You can try this.if it is convenient to you.
HashMap map=new HashMap();
HashSet set=new HashSet();
FileInputStream fis=new FileInputStream(file);
StreamTokenizer st=new StreamTokenizer(fis);
while(st.nextToken()!=StreamTokenizer.TT_EOF){
Integer count=1;
String s;
switch(st.ttype)
{
case StreamTokenizer.TT_WORD:
s=st.sval;
if(map.containsKey(s))
{
count=(Integer)map.get(s);
count++;
map.put(s,count);
set.add(s);
}
else
{
map.put(s,count);
set.add(s);
}
break;
}
}
//now you have a collection of words with their frequency.it will automatically sort numeric values
System.out.println("frequency of each word in file");
Iterator iter=set.iterator();//get all the keys from the HashSet
//display them with help of Iterator interface
while(iter.hasNext())
{
String s=(String)iter.next();
Integer count=(Integer)map.get(s);
System.out.println("frequency of "+s+" : "+count);
}
Most of the answers here are either too complicated or don't implement frequency distribution properly. Following is my solution:
Map<String, Integer> frequency = new HashMap<>();
try (Scanner scanner = new Scanner(new File("path/to/file"), "UTF-8")) {
while (scanner.hasNext()) {
String temp = scanner.nextLine();
if(frequency.containsKey(temp)) {
Integer count = frequency.get(temp);
frequency.put(temp, Integer.sum(count, 1));
} else {
frequency.put(temp, 1);
}
}
}
The key of the Map contains the animal name and value (which is an Integer) contains the occurrences of the animal names read so far. After each iteration, check if the animal name is in the key. If yes, increment its value. Otherwise, put a new key-value pair with the value as 1. Once the Map has been populated, you can use it as you please.
You can do this with Java 8 Streams. This solution is compact and quite expressive. It creates a Stream of lines read from the file. Each unique line becomes a group, it counts the entries in each group, and then sorts the groups by their value, in descending order.
Now since you want to put these in a JTable, you need a two dimentional array.
package com.test;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.swing.JTable;
public class TestCount {
public static void main(String args[]) throws URISyntaxException, IOException {
// for absolute path use: Paths.get("/path/to/animals.txt")
try (Stream<String> stream = Files.lines(Paths.get(TestCount.class.getClassLoader().getResource("animals").toURI()))) {
Object[][] data = stream
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting())).entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.map((entry) -> new Object[] { entry.getKey(), entry.getValue() })
.toArray(Object[][]::new);
// print the data
for (Object[] row : data) {
System.out.println(Arrays.toString(row));
}
// create the JTable
new JTable(data, new String[] { "animal", "count" });
}
}
}
If you already have a sorted Map you can covert to a two dimensional array like so:
Object[][] data = m1.entrySet().stream()
.map((entry) -> new Object[] { entry.getKey(), entry.getValue() })
.toArray(Object[][]::new);
Related
This question already has answers here:
Finding the smallest and second smallest value in an array Java
(3 answers)
Closed 8 years ago.
For my programming class I need to write a method where the code prints the fastest and the second fastest runner.
This is what I've got:
import java.util.Arrays;
class Marathon {
public static void main (String[] arguments){ `
`String[] names ={
"Alex", "Clair", "Sarah", "Andy", "Anna", "Bob"
};
int[] times ={
341, 273, 278, 329, 445, 402,
};
for (int i = 0; i < names.length; i++) {
System.out.println(names[i]+ ": " + times[i]);
}
}
}
How do I get it to show only the fastest person (lowest number) and the second fastest person (second lowest number).
Here's one way to find the fastest runner
import java.util.Collections;
import java.util.HashMap;
import java.util.Map.Entry;
class Marathon {
public static void main (String[] arguments){
HashMap<String, Integer>namez = new HashMap<String, Integer>();
namez.put("Alex", 341 );
namez.put("Clair",273 );
namez.put("Sarah",278);
namez.put("Andy",329);
namez.put("Anna",445 );
namez.put("Bob",402);
Integer min = Collections.min(namez.values());
namez.containsValue(min);
for (Entry<String, Integer>entry: namez.entrySet()){
if(entry.getValue()==min){
System.out.println(entry.getKey()+": "+entry.getValue());
String key = entry.getKey();
}
}
}
}
EDIT: Here is actually the way that finds fastest and the second fastest person from your list. It only outputs their names, which are Clair and Sarah. I hope it helps.
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
class Marathon {
public static void main (String[] arguments){
HashMap<Integer, String>namez = new HashMap<Integer, String>();
namez.put(341,"Alex");
namez.put(273,"Clair");
namez.put(278, "Sarah");
namez.put(329,"Andy");
namez.put(445,"Anna");
namez.put(402, "Bob");
ArrayList<Integer> timez = new ArrayList<Integer>();
timez.add(341);
timez.add(273);
timez.add(278);
timez.add(329);
timez.add(445);
timez.add(402);
Collections.sort(timez);
System.out.println(namez.get(timez.get(0)));
System.out.println(namez.get(timez.get(1)));
}
}
This is probably the most compact way to do it:
import java.util.*;
public class Main {
public static void main(String[] args) {
//Create the mapping:
TreeMap<Integer, String> timeToNameMapping = new TreeMap<Integer,String>();
timeToNameMapping.put(341, "Alex");
timeToNameMapping.put(273, "Clair");
timeToNameMapping.put(278, "Sarah");
timeToNameMapping.put(329, "Andy");
timeToNameMapping.put(445, "Anna");
timeToNameMapping.put(402, "Bob");
//Get the keys from the above mapping.
//Since it is a TreeMap, the keys are sorted
List<Integer> times = new ArrayList<>(timeToNameMapping.keySet());
//Print the result
System.out.println("First: " + timeToNameMapping.get(times.get(0)));
System.out.println("Second: " + timeToNameMapping.get(times.get(1)));
}
}
Output:
First: Clair
Second: Sarah
Explanation:
I am using the reverse mapping, as this enables you to just sort all the keys, and then map the first two elements of the sorted list to the names in the TreeMap (given a runtime the TreeMap above will tell you the name of the runner for that time). TreeMaps are already ordered, but since they keys in the Map are in a TreeSet we cannot use index on it to get the two first elements. That is why I convert the keySet() to an ArrayList (which allows for indexing).
To elaborate on dictionaries (Maps):
Generally when using Lists you use the get() method to get a specific element. For Lists like ArrayList and LinkedList the get() method takes an integer (an index value) and returns the element that are at that position in the list.
Maps are a bit different: Maps make a correlation between a key and a value. In the above example if I give the map the key 341, then it will give me the value "Alex". The get() method on a Map therefore takes a key of type K (in this case an Integer, but it can be any kind of object actually) and returns a value of type V (in this case a String, but can also be any object). The type of the key and value are determined when creating the Map (in this case K, V = Integer, String). The concept of telling the map exactly what types are being used are called generics.
You want to sort the array first and then print out the first two in the array. Because it is for your class I wont give you the code that you need but I gave you the perfect hint all you have to do is google how to sort the array and call on first two. Google Keyswords "Java Sort Array"
I have this input:
5
it
your
reality
real
our
First line is number of strings comming after. And i should store it this way (pseudocode):
associative_array = [ 2 => ['it'], 3 => ['our'], 4 => ['real', 'your'], 7 => ['reality']]
As you can see the keys of associative array are the length of strings stored in inner array.
So how can i do this in java ? I came from php world, so if you will compare it with php, it will be very well.
MultiMap<Integer, String> m = new MultiHashMap<Integer, String>();
for(String item : originalCollection) {
m.put(item.length(), item);
}
djechlin already posted a better version, but here's a complete standalone example using just JDK classes:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class Main {
public static void main(String[] args) throws Exception{
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String firstLine = reader.readLine();
int numOfRowsToFollow = Integer.parseInt(firstLine);
Map<Integer,Set<String>> stringsByLength = new HashMap<>(numOfRowsToFollow); //worst-case size
for (int i=0; i<numOfRowsToFollow; i++) {
String line = reader.readLine();
int length = line.length();
Set<String> alreadyUnderThatLength = stringsByLength.get(length); //int boxed to Integer
if (alreadyUnderThatLength==null) {
alreadyUnderThatLength = new HashSet<>();
stringsByLength.put(length, alreadyUnderThatLength);
}
alreadyUnderThatLength.add(line);
}
System.out.println("results: "+stringsByLength);
}
}
its output looks like this:
3
bob
bart
brett
results: {4=[bart], 5=[brett], 3=[bob]}
Java doesn't have associative arrays. But it does have Hashmaps, which mostly accomplishes the same goal. In your case, you can have multiple values for any given key. So what you could do is make each entry in the Hashmap an array or a collection of some kind. ArrayList is a likely choice. That is:
Hashmap<Integer,ArrayList<String>> words=new HashMap<Integer,ArrayList<String>>();
I'm not going to go through the code to read your list from a file or whatever, that's a different question. But just to give you the idea of how the structure would work, suppose we could hard-code the list. We could do it something like this:
ArrayList<String> set=new ArrayList<String)();
set.add("it");
words.put(Integer.valueOf(2), set);
set.clear();
set.add("your");
set.add("real");
words.put(Integer.valueOf(4), set);
Etc.
In practice, you probably would regularly be adding words to an existing set. I often do that like this:
void addWord(String word)
{
Integer key=Integer.valueOf(word.length());
ArrayList<String> set=words.get(key);
if (set==null)
{
set=new ArrayList<String>();
words.put(key,set);
}
// either way we now have a set
set.add(word);
}
Side note: I often see programmers end a block like this by putting "set" back into the Hashmap, i.e. "words.put(key,set)" at the end. This is unnecessary: it's already there. When you get "set" from the Hashmap, you're getting a reference, not a copy, so any updates you make are just "there", you don't have to put it back.
Disclaimer: This code is off the top of my head. No warranties expressed or implied. I haven't written any Java in a while so I may have syntax errors or wrong function names. :-)
As your key appears to be small integer, you could use a list of lists. In this case the simplest solution is to use a MultiMap like
Map<Integer, Set<String>> stringByLength = new LinkedHashMap<>();
for(String s: strings) {
Integer len = s.length();
Set<String> set = stringByLength.get(s);
if(set == null)
stringsByLength.put(len, set = new LinkedHashSet<>());
set.add(s);
}
private HashMap<Integer, List<String>> map = new HashMap<Integer, List<String>>();
void addStringToMap(String s) {
int length = s.length();
if (map.get(length) == null) {
map.put(length, new ArrayList<String>());
}
map.get(length).add(s);
}
I have a project that I'm working on for my Java class (obviously) and I must have missed the lecture on how to interact with TreeMaps. I have no idea what I'm doing with this part and I'm not finding a lot of help from Google.
For the first case in the program, I have to print all values of a TreeMap. The following is the code I was provided and the work I have done with it. Everything in case A is mine, but it isn't working. Any help would be appreciated.
import java.util.Scanner;
import java.util.Set;
import java.util.Map;
import java.util.TreeMap;
import java.io.File;
import java.io.FileNotFoundException;
public class prog7 {
public static void main(String args[])
throws FileNotFoundException
{
Scanner kb=new Scanner(System.in);
/*here, add code to declare and create a tree map*/
TreeMap treeMap = new TreeMap();
/*here, add code to declare a variable and
let it be the key set of the map
*/
String key;
//temporary variables
String tempWord;
String tempDef;
//the following code reads data from the file glossary.txt
//and saves the data as entries in the map
Scanner infile=new Scanner(new File("glossary.txt"));
while(infile.hasNext())
{
tempWord=infile.nextLine();
tempDef=infile.nextLine();
/*here, add code to add tempWord and tempDef
as an entry in the map
*/
treeMap.put(tempWord, tempDef);
}
infile.close();
while(true)
{
System.out.println();
System.out.println();
//show menu and prompt message
System.out.println("Please select one of the following actions:");
System.out.println("q - Quit");
System.out.println("a - List all words and their definitons");
System.out.println("b - Enter a word to find its definition");
System.out.println("c - Add a new entry");
System.out.println("d - Delete an entry");
System.out.println("Please enter q, a, b, c or d:");
String selection=kb.nextLine(); //read user's selection
if (selection.equals("")) continue; //if selection is "", show menu again
switch (selection.charAt(0))
{
case 'q':
System.out.println("\nThank you.");
return;
/*write code for the cases 'a','b','c' and 'd'
so that the program runs as in the sample run
*/
case 'a':
for (String treeKey : treeMap.keySet())
System.out.println(treeKey);
break;
Iterate over the entrySet rather than the keySet. You get a set of Map.Entry<K, V> which have convenient getKey() and getValue() methods.
That said, Java's standard Map implementations have an implementation of toString() that does what you want. Of course, I reckon you'll only get points for reimplementing it, not for cleverly avoiding it...
for (Map.Entry<K, V> entry : myMap.entrySet()) {
System.out.println("Key: " + entry.getKey() + ". Value: " + entry.getValue());
}
You can use entrySet(). Every Map in java have this method.
Map<String, String> tree = new TreeMap<String, String>();
tree.put("param1", "value1");
tree.put("param2", "value2");
for (Entry<String, String> entry : tree.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
System.out.printf("%s : %s\n", key, value);
}
for (String treeKey : treeMap.keySet())
That gives you the keys.
Now in that loop, get each value from the treeMap using the key (treeKey), and print it.
You can use treeMap.get(treeKey) inside your loop to get the value for the key. Since this value is a string, you could just do something like:
System.out.println("The value for the current key is " + (String)treeMap.get(treeKey));
With Java 8+ there is no need for a loop: lambda expressions enable you to print all keys and/or values in a neat one-liner:
map.forEach((key, value) -> System.out.println(key + " " + value));
Iterating over the set of keys and then retrieving each value is less efficient than iterating over the set of entries (getEntries()). In the former case, getValue() will have to perform a new lookup each time, while getEntries() can simply return the entire contents of the map.
Static analysers such as FindBugs will give you a warning if you try to retrieve a value inside a iteration over the map's keys.
not specifically about TreeMaps, but about Maps in general - I like this first answer, using Guava: Convert java Map to custom key=value string
I am not trying to duplicate threads here.
My problem is i am piping in a file using msdos called amazon.txt
the file has 637 words in it..
I want a count of unique words.. and not a count of "a", "the" , "this"
which i havent counted for yet in the code..
when i add to a tree set it only has 8 words..
There should be atlest 300 unique words..
count of total file = 637
count2 of treeset = 8
I thought treeset handles duplicates? what am i doing wrong?
The file does contain some ints an $
import java.util.Scanner;
import java.util.ArrayList;
import java.util.TreeSet;
import java.util.Iterator;
import java.util.HashSet;
public class practice1
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
String word;
//String grab;
int count = 0;
int count2 =0;
int count3 =0;
int count4 =0;
int number;
//ArrayList<String> a = new ArrayList<String>();
TreeSet<String> a = new TreeSet<String>();
while (sc.hasNext())
{
word = sc.next();
count++; // 637 words
a.add(word);
if (word.equals("---"))
{
break;
}
}
Iterator<String> it = a.iterator();
while(it.hasNext())
{
string grab = it.next();
count2++; // 8 words
if (grab.equals("---"))
{
break;
}
}
System.out.println("count2");
System.out.println(count2);
System.out.println("count");
System.out.println(count);
System.out.println("\nbye...");
}
}
Your method for counting the number of entries in the TreeSet is to iterate over the Set and stop counting when you first see the string "---".
This isn't correct. You are probably assuming that the order of entries returned by TreeSet.iterator() is the same order as which they were inserted in. That isn't the case:
The elements are ordered using their natural ordering, or by a Comparator provided at set creation time, depending on which constructor is used.
"Natural ordering" here means the results of String.compareTo(String) (since String implements Comparable<String>), which tests for lexicographical order. In other words, a the iterator of a TreeSet<String> returns the items in alphabetical order.
If you want to know the size of your Set, just use size().
I don't see anywhere where you are adding the word into the TreeSet 'a'.
If I'm just missing that (and I might be) I'd bet the problem is that a TreeSet is not guaranteed to iterate in the order of insertion. That is, you add "---" last but there's no reason it won't come out of the iterator 8th and terminate your program.
So I'd say get rid of the check where you see if the iterator returns "---" and see where that gets you.
Had time to verify, change:
if (grab.equals("---"))
{
break;
}
to:
if (grab.equals("---"))
{
//break;
}
and it works as expected.
Good luck!
There is no need to iterate a 2nd time, just replace 2nd loop with
System.out.println("Treeset.size():" + a.size() );
and do not add "---" to treeset in the first loop (assuming this is some kind of end of file marker)
if (word.equals("---"))
{
break;
}
a.add(word);
Using a msdos window I am piping in an amazon.txt file.
I am trying to use the collections framework. Keep in mind I want to keep this
as simple as possible.
What I want to do is count all the unique words in the file... with no duplicates.
This is what I have so far. Please be kind this is my first java project.
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Iterator;
public class project1 {
// ArrayList<String> a = new ArrayList<String>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String word;
String grab;
int count = 0;
ArrayList<String> a = new ArrayList<String>();
// Iterator<String> it = a.iterator();
System.out.println("Java project\n");
while (sc.hasNext()) {
word = sc.next();
a.add(word);
if (word.equals("---")) {
break;
}
}
Iterator<String> it = a.iterator();
while (it.hasNext()) {
grab = it.next();
if (grab.contains("a")) {
System.out.println(it.next()); // Just a check to see
count++;
}
}
System.out.println("I counted abc = ");
System.out.println(count);
System.out.println("\nbye...");
}
}
In your version, the wordlist a will contain all words but duplicates aswell. You can either
(a) check for every new word, if it is already included in the list (List#contains is the method you should call), or, the recommended solution
(b) replace ArrayList<String> with TreeSet<String>. This will eliminate duplicates automatically and store the words in alphabetical order
Edit
If you want to count the unique words, then do the same as above and the desired result is the collections size. So if you entered the sequence "a a b c ---", the result would be 3, as there are three unique words (a, b and c).
Instead of ArrayList<String>, use HashSet<String> (not sorted) or TreeSet<String> (sorted) if you don't need a count of how often each word occurs, Hashtable<String,Integer> (not sorted) or TreeMap<String,Integer> (sorted) if you do.
If there are words you don't want, place those in a HashSet<String> and check that this doesn't contain the word your Scanner found before placing into your collection. If you only want dictionary words, put your dictionary in a HashSet<String> and check that it contains the word your Scanner found before placing into your collection.