Duplicate Book Titles using Exceptions - java

I was given a file that I have to find the duplicates and put them into a new text file. That is the gist of what I am trying to accomplish. Here are the directions I was given:
Your client owns a bookstore, and you will find attached; a text file called Samsbooks.txt with
titles of all the books in the store. Write and Print all the duplicate titles to a file called
SamsDuplicate.txt.
EXAMPLE OUTPUT:
Duplicate Books
Sam’s Bookstore 2021
Jack and Jill
Peter Pan
My Little Pony
Here is my code:
enter code here
//In this program, I will write and print all the duplicate book titles to a new file called
SamsDuplicate.txt.
import java.io.*;
public class bookstore {
public static void main(String[] args) throws IOException {
//Printwriter object for the output file that is called SamsDuplicate.txt.
PrintWriter duplicates = new PrintWriter("SamsDuplicate.txt");
//Bufferreader object for the input file that is called SamsBookstore.txt.
BufferedReader original = new BufferedReader(new
FileReader("C:\\Users\\patti\\Desktop\\Patricks dcom101class\\CSIT
210\\SamsBookstore.txt.docx"));
String begin = original.readLine();
//This while loop will read each line of the SamsBookstore.txt file.
while(begin != null) {
boolean in_stock = false;
//This Bufferreader object is for the output file SamsDuplicate.txt.
BufferedReader output = new BufferedReader(new FileReader("SamsDuplicate.txt"));
String mid = output.readLine();
//This while loop will read each line of the SamsDuplicate.txt file.
while(mid != null) {
if(begin.equals(mid)) {
in_stock = true;
break;
}
mid = output.readLine();
}
//This if statement is if the boolean is false and will also write line from SamsBookstore
file to SamsDuplicate file.
if(!in_stock) {
duplicates.println(begin);
}
begin = original.readLine();
}
//Closing both files.
original.close();
duplicates.close();
System.out.println("Duplicate Books");
System.out.println("Sam's Bookstore 2021");
System.out.println();
System.out.println();
}
}
I cannot use HashMaps or anything of that nature since I have not learned about it yet. I have tried putting in the last System.out.println line: my printerwriter (duplicates), my bufferreader(output), even the name of the new file I created called SamsDuplicate.txt none of them will display the duplicates. Am I missing something here? Any help would be appreciated thanks!

Can you use Set?
Based on your code, it seems that the Samsbooks.txt has a book name per line, right?
Set has a method add, declared boolean add(E e). It returns true if the element was added and false if it was not because it already exists in the collection.
If you cannot use Set, you can implement similar functionality by storing each book name in an array. You'll need to first check if the current book name is already in the array. If it is not, then resize the array +1 and add the new book name to the end.

Related

How can I parse lines of data from file to populate objects for each?

I have a text file with the list inside, every line has data that I need insert in the new objects. So data looks like somename=3000 or another type with the slash data another type = 6000.
I have particular class "Item" that has String and int variable. Data need to be inserted into them. Every new object has to be added to the ArrayList<Item>.
// Calculate the lines for next for each loop
int lineCount = 0;
while (sc.hasNextLine()) {
lineCount++;
sc.nextLine();
}
for (int i = 0; i < lineCount; i++) {
// creating the object
Item item = new Item();
// add item object to items ArrayList
items.add(item);
// add line to String variable lineToString,
while (scaner.hasNextLine()) {
String lineToString = scaner.nextLine();
sc.nextLine();
}
So, I figured out that to do this, I need to
copy the whole line and put into some string variable;
split it for integer and string variable;
insert string parts to the String variable and numbers to the int variable in particular object that was created in iteration time of "for loop".
add the object with a data inside to the ArrayList.
I used Scanner to read a text file. When I try to insert the scaner.nextLine to the String it's doesn't work; I mean it's executing but variable String lineToString doesn't have the line from a text file.
Could somebody help with an idea of how better to proceed with this problem? Maybe there is some simpler way to insert the 2 different type of data from the text file line in the object and put it into the ArrayList? Every line in the text file has different data and has to be in different objects.
You didn't mention clearly the line format from the text file. I assume so far you have text file in which each line is like
someone=140000
And you are trying to read those lines of the text and parse each of them to an object of Item which contains a String property (I assume you name it name) and an int property (I assume you name it number)
If this is it, you fisrt need to read your text file line by line and process it further. There are several ways to read a text file line by line.
BufferReader
This is a very common and so far most appropriate way to read a text file in consider of performance.
List<Item> particulatItems = new ArrayList<>();
// using try-with-resource that will help closing BufferedReader by own
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
particularItems.add(processLine(line));
}
}
Scanner
You could use Scanner too.
try (Scanner scanner = new Scanner(new File(fileName))) {
while (scanner.hasNext()) {
particularItems.add(processLine(line));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
You should extract the line processing logic to a independent function. This is good practice of clean coding.
public static Item processLine(Strinng line) {
String[] tokens = line.split("=");
Item item = new Item(tokens[0], tokens[1]);
}
Assuming you have that particular object defined as Item and you are populating a List of this type
public class Item {
String name;
int number;
public Item(String name, String numtxt) {
this.name = name;
this.number = Integer.parseInt(numtxt);
}
// setter getter
}
More reading:
How to read a large text file line by line using Java?
Different ways of Reading a text file in Java
Difference between Scanner vs BufferReader
Try-with-resources in Java 7
Looks like you have already scanned full file in below code snippet:
while (sc.hasNextLine()) {
lineCount++;
sc.nextLine();
}
After this, you are again iterating in for-loop but with same scanner, which has read last line
So the following may return false:
while (scaner.hasNextLine())
I it may never enter while loop
You should reset scanner before iterating lines again .. or may be use something else than scanner to count lines
Apart from what #Ashish Mishra mentioned, you are doing the second while loop in a for loop, why? Isn't one loop sufficient?
int lineCount = 0;
while (sc.hasNextLine()) {
lineCount++;
String lineToString = sc.nextLine();
Item item = new Item();
//convert lineToString to item
items.add(item);
}

How to only get one output from a loop when testing a HashSet

I am building a program which is supposed to tell if a list of words from a text file are all unique or if there is a duplicate using a HashSet. If there is a duplicate, the only output should be "NOT_UNIQUE", and if there are no duplicates, the output should be "UNIQUE".
I believe the way to do this is to add the words from the file to the HashSet, and if a word can't be added it is because that word is a duplicate. I have already started building the program, but the program outputs "UNIQUE" for every word as opposed to just once at the end of the program. I think this has to do with my use of a while-loop and infile.readLine(), but I'm not sure what else to do here. Thank you for your help. My code is below:
import java.io.*;
import java.util.*;
public class Lab5
{
public static void main (String[] args) throws Exception
{
HashSet<String> set = new HashSet<String>();
BufferedReader infile = new BufferedReader( new FileReader( args[0] ) );
while ( infile.ready() )
{
String word = infile.readLine();
if ( !set.add(word) )
System.out.println("NOT_UNIQUE \n");
else
System.out.println("UNIQUE \n");
}
}
}
Flags aren't elegant, but in this case I think it's a pragmatic solution. You can set a flag and bail out of the loop if you don't want it to display for every word:
import java.io.*;
import java.util.*;
public class Lab5
{
public static void main (String[] args) throws Exception
{
boolean isUnique = true;
HashSet<String> set = new HashSet<String>();
BufferedReader infile = new BufferedReader( new FileReader( args[0] ) );
while ( infile.ready() )
{
String word = infile.readLine();
if ( !set.add(word) ) {
isUnique = false;
break;
}
}
System.out.println(isUnique ? "UNIQUE \n" : "NOT_UNIQUE \n");
}
}
Remember to close out your file descriptor if you put this into an application.
You are printing your UNIQUE or NOT_UNIQUE outputs in a loop while your BufferedReader is ready to be read, at each line read, so it'll print a value for each line that's been read.
You probably want to refactor your design here.
The logic below applies only if you want to actually keep the whole of the data read from file, otherwise there will be more efficient solutions, (see Max Mammel's).
Read all the lines from the file
Store them in a List (allows duplicates)
When done reading, initialize a new Set passing your List in its constructor (that'll trim it into a set of unique Strings)
Then compare the sizes of both - if they're different, you have non-unique items
Off-topic: remember to close your streams!

Variable Scope - JAVA Class/Method

I am reading in data from a text file into an ArrayList and then trying to search for a particular string in that ArrayList (the second method).
I believe that I am correctly reading in the data however am struggling to write methods to implement on the ArrayList once it has been filled. For instance, in the checking method below, it is returning a false when I am certain the input String is in the data structure.
I recognize this is likely a problem with my variable scope or how my methods are interacting with each other (i.e, the arraylist is not actually filled with the data when I am checking it).
Any help would be much appreciated - thanks
import java.util.*;
import java.io.*;
public class Word {
ArrayList<String> diclist = new ArrayList<String>();
private void readIn() throws FileNotFoundException {
File file = new File("filepath");
Scanner s = new Scanner(file);
s.useDelimiter("\n");
while (s.hasNextLine()) {
diclist.add(s.nextLine());
}
s.close();
}
public boolean checkIn(String z) {//Check if input string z is in diclist
for (int i = 0; i < diclist.size(); i++) {
if (diclist.get(i).equals(z)) {return true;}
}
return false;
}
}
There are no obvious problems in the code you posted so far. After calling readIn, if the file exists, readable and not empty, the list should get populated. I suggest running it through a debugger.
Note that the checkIn method can be vastly simplified to this:
return diclist.contains(z);

Better way to split my results from reading file?

I have a function that reads through a file, and gathers the results into an array list.
The array list looks like this (data)
[12, adam, 1993, 1234, bob, 1992]
I then need to load these details into new objects called patients. This is the current method I have so far for putting each separate array list item into its own patient, yet it keeps bugging me with an error saying I am passing in String String Int, and it needs to be a String.
s looks like this
12, adam, 1993
And this is the code
public void loadPatients()throws Exception
{
ArrayList<String> data = IO_Support.readData("PatientData.txt");
System.out.println(data);
for(String s : data)
{
Sytem.out.println(s);
patientList.add(new Patient(s));
}
}
Is there a way to push my array list result into a string for passing into the patient object, or should I use a different way to split the string results?
Read data looks like this
public static ArrayList<String> readData(String fileName) throws Exception
{
ArrayList<String> data = new ArrayList<String>();
BufferedReader in = new BufferedReader(new FileReader(fileName));
String temp = in.readLine();
while (temp != null)
{
data.add(temp);
temp = in.readLine();
}
in.close();
return data;
}
while (temp != null)
{
temp = in.readLine();
}
First thing, You are never adding your input to the ArrayList.. This while loop makes no sense.. It is just reading user input, and swallowing it on every occassion..
Plus, after seeing your exception, its sure that you are using a 1-arg constructor of Patient class which is not there.. There are only 0-arg constructor and 2-arg constructor in Patient class.. You need to use them indeed.
See this code in loadPatient method.. You need to add a 1-arg constructor in your Patient class to get it compiled..
patientList.add(**new Patient(s)**); --> Will not work
So, in your Patient class, add: -
public Patient(String s) {
this.s = s;
}
this.s is the instance variable to store s that you passed..

To have efficient many-to-many relation in Java

How can you make the efficient many-to-many -relation from fileID to Words and from word to fileIDs without database -tools like Postgres in Java?
I have the following classes.
The relation from fileID to words is cheap, but not the reverse, since I need three for -loops for it.
alt text http://img191.imageshack.us/img191/4077/oliorakenne1.png
My solution is not apparently efficient.
Other options may be to create an extra class that have word as an ID with the ArrayList of fileIDs.
Reply to JacobM's answer
The relevant part of MyFile's constructors is:
/**
* Synopsis of data in wordToWordConutInFile.txt:
* fileID|wordID|wordCount
*
* Synopsis of the data in the file wordToWordID.txt:
* word|wordID
**/
/**
* Getting words by getting first wordIDs from wordToWordCountInFile.txt and then words in wordToWordID.txt.
*/
InputStream in2 = new FileInputStream("/home/dev/wordToWordCountInFile.txt");
BufferedReader fi2 = new BufferedReader(new InputStreamReader(in2));
ArrayList<Integer> wordIDs = new ArrayList<Integer>();
String line = null;
while ((line = fi2.readLine()) != null) {
if ((new Integer(line.split("|")[0]) == currentFileID)) {
wordIDs.add(new Integer(line.split("|")[6]));
}
}
in2.close();
// Getting now the words by wordIDs.
InputStream in3 = new FileInputStream("/home/dev/wordToWordID.txt");
BufferedReader fi3 = new BufferedReader(new InputStreamReader(in3));
line = null;
while ((line = fi3.readLine()) != null) {
for (Integer wordID : wordIDs) {
if (wordID == (new Integer(line.split("|")[1]))) {
this.words.add(new Word(new String(line.split("|")[0]), fileID));
break;
}
}
}
in3.close();
this.words.addAll(words);
The constructor of Word is at the paste.
Wouldn't a more efficient approach be to assign the link from Word to MyFile at the point that you know the Word is in the File? That is to say, how do you build the list of Words in the MyFile object? If you're reading the words in to the MyFile out of, say, a file on the filesystem, than as you read in each word, you assign its MyFile to the current file.
//within MyFile constructor or setter for Words
while (//there's another word to add) {
Word newWord = new Word(//read word from file);
words.add(newWord);
newWord.setMyFile(this);
}
This is akin to the typical way to manage a bidirectional parent-child relationship:
//in Parent
public void addChild(Child child) {
myChildren.add(child);
child.setParent(this);
}
It might help if you show us how you build the MyFile object.
Edited after you added the code that builds the list of Words:
OK, so having seen the code that builds your Words, I don't think setting up the relationship is the source of your inefficiencies. It looks like you are setting up the relationship in exactly the way I suggested (as you add each word, you give that word the fileID of the corresponding file).
It looks like the source of your inefficiencies are that, for each word, you have to match it up with various things that you currently have in a set of files (e.g. WordToWordId). So for every word you have to loop through every line of that file, and find the match. This is certainly inefficient.
The better approach is to have those pairings in memory in a HashMap, initialized at startup. That way, if you have a particular word and need the corresponding ID, or vice versa, you look them up in your HashMap, which is a constant-time operation. Similarly, for each word, you are looping through every file; again, do that loop ONCE, and store the result in a HashMap. Then lookups become constant time.
Both classes should override hashCode and equals. Thus you will decide what is equal.
Then you will create a set in each of your classes.
public class MyFile implements Comparable<MyFile> {
//your fields here
Set<Word> words = new HashSet<Word>(0);
//Remember to override hashCode and equals
}
public class Word implements Comparable<Word> {
//your fields here
Set<MyFile> words = new HashSet<MyFile>(0);
//Remember to override hashCode and equals
}
In your sets now you will have all the MyFiles.words and otherway around, all the Words.myFile
I think you want that the file know it's words and the words know the files where it is used.
public class File {
private List<Word> words;
public File(){
words=new Vector<Word>();
}
/**
*The method add word to word list.
**/
public addWord(Word word){
this.words.add(word);
word.addFile(this);
}
}
public class Word{
List<File> files;
public addFile(File file){
this.files.add(file);
}
}
or vice versa... but you should question GRASP Design pattern.Maybe your data type is wrong (I dont say wrong because itis your desing,so i respect).

Categories