This is for my beginning Java class. There are similar questions asking to sort the values that are given in an array; I know how to do that, but here I need to read in a text file, and then sort the values and display them by employee name and the hours that they worked, while also keeping the order from most to least. This is what the text file looks like:
Jim 4 5 6 1 2 3 4
Harry 6 5 1 3 9 2 0
John 2 3 1 6 7 8 4
Lisa 2 1 5 4 1 2 6
And here is all that I know about reading in text files and my current code for this project.
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
public class EmployeeWorkHours {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
File file = new File("/Users/ODonnell/Desktop/inputData.txt");
try {
Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
Parsing
Look at the Javadoc for java.util.Scanner, or use autocomplete in your IDE, you'll see a lot more methods than nextLine() etc, the ones of interest
hasNextInt() returns true when next token is a number
nextInt() the next integer
Storage
Now you need to store your numbers, I'd recommend a List as you won't know how many there are upfront which rules out primitive arrays.
Create a list with List hours = new ArrayList();
Add to it with add()
You'll also need to store your employees names, for simplicity I'd recommend using a Map of String to hours list, i.e. Map>.
Create with Map> employeeHours = new HashMap>()
Add to using employeeHours.put(name, hours)
Sorting
java.util.Collections.sort is all you need. This will sort your list by default in ascending order.
Displaying
Most if not all built in list implementations by default implement toString() so you can simply call System.out.println(hours)
You should save the hours worked and the names of your employees in a HashMap.
http://en.wikipedia.org/wiki/Hash_table For an explation of a HashMap.
After storing your values you can sort the HashMap like it is explained in the following link:
Sort a Map<Key, Value> by values (Java)
You should use next() method on scanner instance to read next token instead of whole line. Then you have to try to parse it to integer to recognize if it is a name of employee or its work hour. In the for loop we are sorting data (using Collections utility class) and printing it.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
public class EmployeeWorkHours {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
File file = new File("inputData.txt");
Map<String, List<Integer>> data = new HashMap<String, List<Integer>>();
try {
Scanner scanner = new Scanner(file);
List<Integer> currentEmployee = null;
while (scanner.hasNextLine()) {
String token = scanner.next();
try {
currentEmployee.add(new Integer(token));
} catch (NumberFormatException e) {
currentEmployee = new ArrayList<Integer>();
data.put(token, currentEmployee);
}
}
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
for (String name : data.keySet()) {
Collections.sort(data.get(name));
Collections.reverse(data.get(name));
System.out.println(name + " " + data.get(name));
}
}
}
Related
I am creating a program that takes two .txt files and prints out the words that appear in both texts and the number of times each shared word appears in each text. I declared two file objects that have valid paths. However, when I try to create two Scanner objects that use the two .txt files, I get FileNotFoundException compiler errors for both lines of code that are declaring the new Scanner objects.
FYI, I use scannerObject.hasNext() in a while loop that adds each word from scannerObject.Next() as a new key in a HashMap variable with a value of 1 or, if the word is already a key in the HashMap, increasing the value (number of occurrences) by 1.
I have tried running the following with both file paths and the simple program below runs without error and outputs "It worked! Hehehe":
import java.io.*;
import java.util.*;
public class readingFilesPractice {
public static void main(String[] args) {
try{
File x = new File("C:\\Users\\aravd.000\\Desktop\\Book1.txt");
Scanner sc = new Scanner(x);
while(sc.hasNext()){
System.out.println(sc.next());
}
sc.close();
System.out.println("It worked! Hehehe");
}
catch (Exception e){
System.out.println("Error!");
}
}
}
By the way, the .txt files has areas where there are multiple spaces in succession and stuff like "1.".
The code below runs into two FileNotFoundExceptions (without the try and catch blocks) and in Visual Studios, new Scanner(book1) and new Scanner(book2) have a red squiggly line that states "Unhandled exception type FileNotFoundExceptionJava(16777384)" when I hover over it with my mouse. My complete code for reference is below.
import java.io.*;
import java.util.*;
public class program1 {
public static void main(String[] args) {
try {
File book1 = new File("C:\\Users\\aravd.000\\Desktop\\Book1.txt");
File book2 = new File("C:\\Users\\aravd.000\\Desktop\\Book2.txt");
// Counting the number of occurences of each word in book1
Scanner readBook1 = new Scanner(book1);
HashMap<String, Integer> wordsInBook1 = new HashMap<String, Integer>();
while (readBook1.hasNext()) {
String word = readBook1.next();
if (wordsInBook1.containsKey(word)) {
int occurences = wordsInBook1.get(word) + 1;
wordsInBook1.put(word, occurences);
} else {
wordsInBook1.put(word, 1);
}
}
readBook1.close();
// Counting the number of occurences of each word in book2
Scanner readBook2 = new Scanner(book2);
HashMap<String, Integer> wordsInBook2 = new HashMap<String, Integer>();
while (readBook2.hasNext()) {
String word = readBook2.next();
if (wordsInBook2.containsKey(word)) {
int occurences = wordsInBook2.get(word) + 1;
wordsInBook2.put(word, occurences);
} else {
wordsInBook2.put(word, 1);
}
}
readBook2.close();
// Creating two iterators for each HashMap
Iterator wordsInB1Iter = wordsInBook1.entrySet().iterator();
Iterator wordsInB2Iter = wordsInBook2.entrySet().iterator();
// Running the wordsInB1Iter iterator to find and delete unique keys in
// wordsInBook1
while (wordsInB1Iter.hasNext()) {
Map.Entry pair = (Map.Entry) wordsInB1Iter.next();
if (!wordsInBook2.containsKey(pair.getKey())) {
wordsInBook1.remove(pair.getKey());
}
}
// Running the wordsInB2Iter iterator to find and delete unique keys
while (wordsInB2Iter.hasNext()) {
Map.Entry pair = (Map.Entry) wordsInB2Iter.next();
if (!wordsInBook1.containsKey(pair.getKey())) {
wordsInBook2.remove(pair.getKey());
}
}
System.out.println(wordsInBook1);
System.out.println(wordsInBook2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
If the other parts of the code are broken, I wouldn't know because I haven't debugged that yet. If you find an error elsewhere, let me know if you want. Thank you for your effort and please let me know if there's anything that needs further clarification!
UPDATE: When I changed my catch block to Exception e and used the e.printStackTrace, my code outputted the following:
java.util.ConcurrentModificationException
at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1493)
at java.base/java.util.HashMap$EntryIterator.next(HashMap.java:1526)
at java.base/java.util.HashMap$EntryIterator.next(HashMap.java:1524)
at prorgam1.main(program1.java:50)
Link to error descriptions within the "PROBLEMS" tab in VisualStudios
The picture above may provide more details about the issues with my iterators and HashMaps.
The same answer than #Pedro Borges but
Please use generics! Your code is full of cast while it should not.
Use Iterator.remove() to remove current value instead of using the source collection. This is the reason your are getting a ConcurrentModificationException.
If you don't need the Map.Entry, you may use keySet() instead.
You are using Java > 8. If this is Java 11, you may also use var.
Your code:
Iterator<Map.Entry<String, Integer>>> wordsInB1Iter = wordsInBook1.entrySet().iterator();
Iterator<Map.Entry<String, Integer>>> wordsInB2Iter = wordsInBook2.entrySet().iterator();
// Running the wordsInB1Iter iterator to find and delete unique keys in
// wordsInBook1
while (wordsInB1Iter.hasNext()) {
Map.Entry<String,Integer> pair = wordsInB1Iter.next();
if (!wordsInBook2.containsKey(pair.getKey())) {
wordsInB1Iter.remove();
}
}
// Running the wordsInB2Iter iterator to find and delete unique keys
while (wordsInB2Iter.hasNext()) {
Map.Entry<String,Integer> pair = wordsInB2Iter.next();
if (!wordsInBook1.containsKey(pair.getKey())) {
wordsInB2Iter.remove();
}
}
And while I'm at it, you may also consider refactoring how your read words:
By using a method instead of duplicating the code
By using try with resource (Java 7++)
By using Map.merge (Java 8++)
As in:
void words(File file) {
try (Scanner scanner = new Scanner(file)) {
var result = new HashMap<String,Integer>();
while (scanner.hasNext()) {
var word = scanner.next();
result.merge(word, 1, Integer::sum); // or (a, b) -> a + b
}
return result;
}
}
You may (should?) use a MutableInteger (from common-lang3) to avoid unboxing from Integer to int for performance reasons.
The ConcurrentModificationException comes from the fact you are removing elements from a Set while you're iterating it. That happens because under the hood the iterator is backed by the set, it's not a copy of it.
One way to corner it, although not tremendously elegant is to iterate over a copy of the Set.
If you replace
Iterator wordsInB1Iter = wordsInBook1.entrySet().iterator();
Iterator wordsInB2Iter = wordsInBook2.entrySet().iterator();
with
Iterator wordsInB1Iter = new HashSet<>(wordsInBook1.entrySet()).iterator();
Iterator wordsInB2Iter = new HashSet<>(wordsInBook2.entrySet()).iterator();
you will no longer have concurrent modification.
My problem is that I created an array from a csv file and I now have to output any values with duplicates.
The file has a layout of 5x9952. It consists of the data:
id,birthday,name,sex, first name
I'd now like the program to show me in each column (e.g. name) which duplicates there are. Like if there are two people which the same name. But whatever I try from what I found on the Internet only shows me the duplicates of rows (like if name and first name are the same).
Here's what I got so far:
package javacvs;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
*
* #author Tobias
*/
public class main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
String csvFile = "/Users/Tobias/Desktop/PatDaten/123.csv";
String line = "";
String cvsSplitBy = ",";
try (BufferedReader br = new BufferedReader(new FileReader(csvFile))) {
while ((line = br.readLine()) != null) {
// use comma as separator
String[] patDaten = line.split(cvsSplitBy);
for (int i = 0; i < patDaten.length-1; i++)
{
for (int j = i+1; j < patDaten.length; j++)
{
if( (patDaten[i].equals(patDaten[j])) && (i != j) )
{
System.out.println("Duplicate Element is : "+patDaten[j]);
}
}
}
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
(I changed the name of the csv as it contains confidential data)
The real thing here: stop thinking "low level". Good OOP is about creating helpful abstractions.
In other words: your first stop should be to create a meaningful class definition that represents the content of one row, lets call it the Person class for now. And then you separate your further concerns:
you create one class/method that does nothing else but reading that CSV file - and creating one Person object per row
you create a meaningful data structure that tells you about duplicates
The later could (for example) some kind of reverse indexing. Meaning: you have a Map<String, List<Person>>. And after you have read all your Person objects (maybe in a simple list), you can do this:
Map<String, List<Person>> personsByName = new HashMap<>();
for (Person p : persons) {
List<Person> personsForName = personsByName.get(p.getName());
if (personsByName == null) {
personsForName = new ArrayList<>();
personsByName.put(p.getName(), personsForName);
}
personsForName.add(p);
}
After that loop that map contains all names used in your table - and for each name you have a list of the corresponding persons.
You are iterating upon the rows instead of iterating upon the column. What you need to do is to have the same cycle but upon the column.
What you can do is to acumulate the names in a separate array and than iterate it. I am sure you know what index is the column you want to compare. So you will need one cycle extra to accumulate the column you want to check for duplications.
It's a bit unclear what you want presented, the whole record, or only that there are duplicate names.
For the name only:
String csvFile = "test.csv";
List<String> readAllLines = Files.readAllLines(Paths.get(csvFile));
Set<String> names = new HashSet<>();
readAllLines.stream().map(s -> s.split(",")[2]).forEach(name -> {
if (!names.add(name)) {
System.out.println("Duplicate name: " + name);
}
});
For the whole record:
String csvFile = "test.csv";
List<String> readAllLines = Files.readAllLines(Paths.get(csvFile));
Set<String> names = new HashSet<>();
readAllLines.stream().forEach(record -> {
String name = record.split(",")[2];
if (!names.add(name)) {
System.out.println("Duplicate name: " + name + " with record " + record);
}
});
Your problem is the nesting of your loops. What you do is, that you read one line, split it up and then you compare the fields of this one row with each other. You do not even compare one line with other lines!
So first you need an array for all lines so you can compare these lines. As GhostCat recommended in his answer you should use your own class Person which has the five fields as attributes. But you could use a second array, so you can work with the indexes as Alexander Petrov said in his answer. In the latter case, you get a two-dimensional array:
String[][] patDaten;
After that you read all lines of your csv-file and for each line you create a new Person or a new inner array.
After reading the entire file, you compare the fields as you want. Here you use your double loop. So you compare patDaten[i].getName() with patDaten[j].getName() or with the array patDaten[i][1] with patDaten[j][1].
i have a program that takes tracks and how many times it was played and output it.. simple.. but i couldn't make the counting in a descending order. My second problem is that if there are multiple tracks with the same count, it should look at the track's name and print them in alphabetical order.. i reached the point where i can print everything as it should be without the order though, because I am using maps and whenever I use a list to sort it out, it gets sorted in ascending order.
Here is my code and output
import java.util.*;
import java.io.*;
import java.lang.*;
import lab.itunes.*;
public class Music {
public static void main(String[] args) throws Exception {
try {
Scanner input = new Scanner(System.in);
PrintStream output = new PrintStream(System.out);
Map<String,Integer> mapp = new HashMap<String,Integer>();
List<Integer> list1 = new ArrayList<Integer>();
output.print("Enter the name of the iTunes library XML file:");
String entry = input.nextLine();
Scanner fileInput = new Scanner(new File(entry));
Library music = new Library(entry); // this class was given to us.
Iterator<Track> itr = music.iterator(); // scan through it
while (itr.hasNext())
{
Track token = itr.next(); // get the tracks
mapp.put(token.getName(),token.getPlayCount()); // fill our map
list1.add(token.getPlayCount()); // fill our list too
}
for(Map.Entry<String,Integer> testo : mapp.entrySet()) {
String keys = testo.getKey();
Integer values = testo.getValue();
output.printf("%d\t%s%n",values,keys); // printing the keys and values in random order.
}
} catch (FileNotFoundException E) {
System.out.print("That file does not exist");
}
}
}
the output is this..
Enter the name of the iTunes library XML file:library.txt
87 Hotel California
54 Like a Rolling Stone
19 Billie Jean
75 Respect
26 Imagine
19 In the Ghetto
74 Macarena
27 Hey Jude
67 I Gotta Feeling
99 The Twist
can you please give me a hint for this? i worked for at least 4 hours to get this far.. thanks
Does the Library class have a sort() method? If not, you could add one and call sort() on the Library music just before you ask it for its iterator().
public class Library
{
// ... existing code ...
public void sort()
{
class TrackPlayCountComparator implements Comparator<Track>
{
#Override
public int compare(Track t1, Track t2) {
int compare = t2.getPlayCount() - t1.getPlayCount();
if (compare == 0) {
return t1.getName().compareTo(t2.getName());
}
return compare;
}
}
Collections.sort(this.tracks, new TrackPlayCountComparator());
}
}
Simplifies your code to this:
public static void main(String[] args) throws Exception
{
Scanner input = new Scanner(System.in);
System.out.print("Enter the name of the iTunes library XML file: ");
String entry = input.nextLine();
try {
input = new Scanner(new File(entry));
input.close();
Library music = new Library(entry); // this class was given to us.
music.sort(); // sort the tracks
PrintStream output = new PrintStream(System.out)
for (Iterator<Track> itr = music.iterator(); itr.hasNext(); ) {
Track track = itr.next();
output.printf("%d\t%s%n", track.getPlayCount(), track.getName());
}
} catch (FileNotFoundException E) {
System.out.print("That file does not exist");
}
}
I'm assuming your question is: how can I sort a map on the values, rather than the keys?
If so, here is some sample code to get you started:
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.map(entry -> entry.getKey() + "\t + entry.getValue())
.forEach(output::println);
If you need to sort in reverse order then just change the comparingByValue comparator:
.sorted(Map.Entry.comparingByValue((val1, val2) -> val2 - val2))
To sort by value then alphabetically:
.sorted((entry1, entry2) -> entry1.getValue() == entry2.getValue() ? entry1.getKey().compareTo(entry2.getKey())) : entry2.getValue() - entry1.getValue())
You could make that a bit neater by putting the comparator in a separate method.
private Comparator<Map.Entry<String, Integer>> songComparator() {
return (entry1, entry2) -> {
int difference = entry2.getValue() - entry1.getValue();
if (difference == 0) {
return entry1.getKey().compareTo(entry2.getKey()));
} else {
return difference;
}
}
}
you would then use songComparator to generate the comparator for sorted.
Use Collections.sort() to sort a collection by its natural order, or define a Comparator and pass it as the second argument.
First you must change your List to take the 'Track' type, and you no longer need a Map:
// the list will store every track
List<Track> tracks = new ArrayList<Track>();
String entry = input.nextLine();
Scanner fileInput = new Scanner(new File(entry));
Library music = new Library(entry); // this class was given to us.
Iterator<Track> itr = music.iterator(); // scan through it
while (itr.hasNext()) {
tracks.add(itr.next()); // add each track
}
// you can define classes anonymously:
Collections.sort(tracks, new Comparator<Track>()
{
#Override
public int compare(Track t1, Track t2) {
int diff = t2.getPlayCount() - t1.getPlayCount();
// if there is no difference in play count, return name comparison
return (diff == 0 ? t1.getName().compareTo(t2.getName()) : diff);
}
});
See Anonymous Classes for more information.
I have a Multidimensional ArrayList, composed of multiple rows of different length. I would like to save the ArrayList as a single tab-delimited file with multiple columns, in which each column corresponds to a specific row of the ArrayList. I have tried to come up with a solution, but the only thing I could think of is to save each ArrayList row in separate files.
The ArrayList is called "array" and it contains several rows of different length. Here is the code:
try {
PrintWriter output = new PrintWriter(new FileWriter("try"));
output.print(array.get(0));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
In this case, I can save the first row of the ArrayList as a single file. The other solution I have been thinking about is to loop through the rows, to get as many separate files as the row numbers. However, I would like to get a single file with multiple tab-delimited columns.
Ecxuse me, my old answer was based on a wrong interpretation of your needs.
I made you an example code:
package com.test;
import java.util.ArrayList;
import java.util.List;
public class MulitArrayList {
public static void main(String[] args) {
List<String> innerArrayList1;
List<String> innerArrayList2;
List<String> innerArrayList3;
List<List> outerArrayList;
innerArrayList1 = new ArrayList<String>();
innerArrayList2 = new ArrayList<String>();
innerArrayList3 = new ArrayList<String>();
//comic heros
innerArrayList1.add("superman");
innerArrayList1.add("batman");
innerArrayList1.add("catwoman");
innerArrayList1.add("spiderman");
//historical persons
innerArrayList2.add("Stalin");
innerArrayList2.add("Gandy");
innerArrayList2.add("Lincoln");
innerArrayList2.add("Churchill");
//fast food
innerArrayList3.add("mc donalds");
innerArrayList3.add("burger king");
innerArrayList3.add("subway");
innerArrayList3.add("KFC");
//fill outerArrayList
outerArrayList = new ArrayList<List>();
outerArrayList.add(innerArrayList1);
outerArrayList.add(innerArrayList2);
outerArrayList.add(innerArrayList3);
//print
for(List<String> innerList : outerArrayList) {
for(String s : innerList) {
System.out.print(s + "\t");
}
System.out.println("\n");
}
}
}
The result is:
As you can see, the results are printed with tabs, but the space between them differentiate. You can write it the same way into your file, but this is not the best way to save data. I hope I could help you bit, greetings.
I am trying to read integers from a text file and store them into an array. The text file reads:
4
-9
-5
4
8
25
10
0
-1
4
3
-2
-1
10
8
5
8
Yet when I run my code I get [I#41616dd6 in the console window...
public static void main(String[] args) throws IOException
{
FileReader file = new FileReader("Integers.txt");
int[] integers = new int [100];
int i=0;
try {
Scanner input = new Scanner(file);
while(input.hasNext())
{
integers[i] = input.nextInt();
i++;
}
input.close();
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println(integers);
}
You're printing out the virtual memory address of the array instead of the actual array items:
You can print out the actual array items, one by one, like this:
// This construct is called a for-each loop
for(int item: integers) {
System.out.println(item);
}
#akuhn points out correctly that Java has a built in helper for this:
System.out.println(Arrays.toString(integers));
Note that you'll need to add:
import java.util.Arrays
in your imports for this to work.
Unfortunately, Java’s designers missed to add a proper string representations for arrays.
Instead use
System.out.println(Arrays.toString(integers));
You need to import java.util.Arrays; to make this work.
instead of this
System.out.println(integers);
try this
System.out.println(integers[0] + " : " + integers[1]);
you need to print actual values in integers[] array not array itself
If using an int array is not a restriction, then i would suggest use List. You can use it like this :
List<Integer> integers = new ArrayList<Integer>();
Scanner input = new Scanner(file);
while(input.hasNext()){
integers.add(scanner.nextInt());
}
System.out.println(integers);
Output : [1,2,-1,23]
Whenever you pass any object to System.out.println(), it prints the toString() for that object. If its not overridden, it prints the memory address of that object.
System.out.println(integers);
is trying to print toString() representation of integer array which is nothing but the JVM address of this array.
To print the actual numbers in the array, you either need to iterate through the array or convert the array to java.util.ArrayList.(which has the toString() method implemented.)
This should help you to read Integer from a file and store it in array
import java.util.Scanner;
import java.io.File;
import java.util.ArrayList;
public class filetoarray {
public static ArrayList<Integer> read(File f)
{
ArrayList<Integer> array=new ArrayList<Integer>();
try
{
Scanner sc=new Scanner(f);
while(sc.hasNextLine())
{
array.add(sc.nextLine());
}
}
catch(Exception e)
{
System.out.printf("ERROR : %s", e);
}
return array;
}
public static void main(String[] args) {
File file1=new File("file1.txt");//your file path here
ArrayList<Integer> array1;
array1=read(file1);
System.out.println(array1);
}
}