File indexing program not working - java

I have to make a program that reads each word a file and makes an index of which lines the word occurs on in alphabetical order.
for example, if the file had:
a white white dog
crowded around the valley
the output should be:
a
around: 2
crowded: 2
dog: 1
the: 2
valley: 1
white: 1, 1
When my file contains:
one fish two fish blue fish green fish
cow fish milk fish dog fish red fish
can you find a little lamb
can you find a white calf
THE OUTPUT IS WRONG!: (NOT IN ALPHA ORDER)
a: 3 4
calf: 4
find: 3 4 4
lamb: 3
little: 3
white: 4
you: 3 4
blue: 1
can: 3
cow: 2
dog: 2
green: 1 1 2 2 2 2
milk: 2
red: 2
two: 1 1 1
fish: 1
one: 1
Here is my code::
INDEXMAKER MASTER CLASS
import java.io.*;
import java.util.*;
public class IndexMaker {
private ArrayList<Word> words;
private String fileName;
private String writeFileName;
public IndexMaker(String fileName, String writeFileName) {
this.fileName = fileName;
this.writeFileName = writeFileName;
words = new ArrayList<Word>();
}
public void makeIndex() {
try {
File file = new File(fileName);
Scanner lineScanner = new Scanner(file);
int lineNum = 0;
while (lineScanner.hasNext()) {
lineNum++;
Scanner wordScanner = new Scanner(lineScanner.nextLine());
while (wordScanner.hasNext()) {
String word = wordScanner.next().toLowerCase();
if (!words.contains(new Word(word))) {
insertInto(word, findPosition(word), lineNum);
} else {
addLineNum(word, lineNum);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void displayIndex() {
try {
//FileWriter fileWriter = new FileWriter(new File(writeFileName));
//BufferedWriter writer = new BufferedWriter(fileWriter);
for (Word word : words)
System.out.println(word.getWord() + ": " + word.getLineNums());
} catch (Exception e) {
}
}
private int findPosition(String word) {
for (int i = 0; i < words.size(); i++) {
if (word.compareTo(words.get(i).getWord()) <= 0)
return i;
}
return 0;
}
private void insertInto(String word, int pos, int lineNum) {
words.add(pos, new Word(word, String.valueOf(lineNum)));
}
private void addLineNum(String word, int lineNum) {
int pos = findPosition(word);
words.get(pos).addLineNum(lineNum);
}
}
WORD CLASS
public class Word {
private String word;
private String lineNums;
public Word(String word, String lineNum) {
this.word = word;
this.lineNums = lineNum;
}
public Word(String word) {
this.word = word;
this.lineNums = "";
}
public String getWord() {
return word;
}
public String getLineNums() {
return lineNums;
}
public void addLineNum(int num) {
lineNums += " " + num;
}
#Override
public boolean equals(Object w) {
if (((Word)w).getWord().equals(word))
return true;
else
return false;
}
}
CLIENT
public class Client {
public static void main(String[] args) {
IndexMaker indexMaker = new IndexMaker("readme.txt", "readme.txt");
indexMaker.makeIndex();
indexMaker.displayIndex();
}
}
any help would be appreciated, thanks.

I can't find your definition of compareTo. It seems this would be the key part of your program?
Properly implement your compareTo and confirm it works properly by printing the results of comparisons using System.out.println
Doing your own comparison is "ok" in that it will work if you do it properly. The other thing you could do would be to implement Comparable and then you can get Java to sort a list of words for you.

Related

Java - Compare frequency of elements of a specific type

my task is to read a file and then print out the most 10 frequent words in the text file.
I have used the following comparator and it gives me correctly the first 3 most frequent words but then it kind of gets it all wrong and it only prints out 9 instead of 10.
Here is my comparator
import java.util.*;
class CompareFreq implements Comparator<HashElement>
{
public int compare(HashElement x, HashElement y)
{
if (y.getCounter() > x.getCounter())
{
return 1;
}
else
{
return -1;
}
}
}
And here is my main:
String[] temp = new String[100000];
Scanner obj = new Scanner(new File("file.txt"));
while (obj.hasNext())
{
String text = obj.nextLine();
for (String t : text.split(" "))
{
set.insert(t);
}
}
System.out.println("All words and the frequency:");
set.printTableInOrderAndFreq();
System.out.println();
System.out.println("Most 10 frequent words:");
set.getMaxWordsFrequency(10);
Here is the output that I am getting
Most 10 frequent words:
to
the
of
their
they
caused
with
companions
great
The first 3 (to, the, of) words are correct, they are the most frequent in my text but then the calculations are wrong. On top of that I believe it is deleting on of the 10 words where you can see there's a blank row between the word 'they' and 'caused'
I forgot to post my HashElement class, here it is
public class HashElement
{
private String word; // ordet
public int counter; // antalet förekomst av ordet
private boolean isActive; // behövs eventuellt för remove
public HashElement(String theword)
{
word = theword;
isActive = true;
}
public void increment()
{
counter++;
}
public int getCounter()
{
counter++;
return counter;
}
public String getWord()
{
return word;
}
public boolean getStatus()
{
return isActive;
}
public boolean changeStatus()
{
isActive = false;
return isActive;
}
}
Thanks for the help in advance

Displaying 5 top scores from txt file java

I've made a card game, similar to solitaire. It's almost finished. The last thing I'm struggling with is printing top 5 scores. Whenever player ends a game it writes into scores.txt file how many piles he's left on a table, let's say 4. So in the .txt file I have following numbers: 1,2,3,4,5,6,7,8,9. How can I print from file top 5 of these, so it's: 1,2,3,4,5.
DeckOfCards class:
import java.io.*;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
public class DeckOfCards {
private ArrayList<Cards> deck;
private int currentCard=-1; //index of the next card to be dealt
private Scanner in;
private int i;
//ArrayList<Integer> indexesToRemove = new ArrayList();
/**
*
* Constructor to build a deck of cards
*/
public DeckOfCards() {
this.deck = new ArrayList<Cards>();
}
public void removeCard(int i) {
this.deck.remove(i);
}
public Cards getCard(int i){
return this.deck.get(i);
}
public void addCard(Cards addCards){
this.deck.add(addCards);
}
//Draws from the deck1
public void draw(DeckOfCards comingFrom){
currentCard++;
this.deck.add(comingFrom.getCard(0));
comingFrom.removeCard(0);
}
public void saveScore(){
try (PrintStream out = new PrintStream(new FileOutputStream("scores.txt"))) {
out.print(deck.size());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
Card class:
public class Cards {
private String suit;
private String value;
public Cards(String suit, String value)
{
this.suit = suit;
this.value = value;
}
public String getSuit() {
return suit;
}
public void setSuit(String suit) {
this.suit = suit;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public String toString() {
return suit + value;
}
}
Hope it helps. I got rid of some methods I believe they aren't useful. There's also the menu and like I said every case works except of displaying top 10 results.
1 - Print the pack out (this is so you can check that it plays properly)
2 - Shuffle
3 - Deal a card
4 - Make a move, move last pile onto previous one
5 - Make a move, move last pile back over two piles
6 - Amalgamate piles in the middle (by giving their numbers)
7 - Print the displayed cards on the command line
8 - Play for me once (if two possible moves, makes the ‘furthest’ move)
9 - Play for me many times
10 - Display top 10 results
When the game is over, read the input file in memory (like in a list), add the new result at the position it should go in the leaderboard, write the new results in the file, then take the five first of the list (element 0 is best score and element n is worst score).
public void endGame(int finalScore) throws IOException {
List<String> scores = retrieveScores();
addNewScore(finalScore, scores);
writeScores(scores);
showLeaderBoard(scores);
}
private List<String> retrieveScores() throws IOException {
BufferedReader reader = new BufferedReader(new FileReader("score.txt"));
String scoreLine = reader.readLine(); // read line that contains scores
List<String> scores = new ArrayList<>();
if (scoreLine != null) { // in case of first game
String[] tempScore = scoreLine.split(", ");
scores = new ArrayList<>(Arrays.asList(tempScore));
}
reader.close();
return scores;
}
private void addNewScore(int finalScore, List<String> scores) {
boolean foundSpotForNewScore = false;
int i = 0;
while (!foundSpotForNewScore && i < scores.size()) {
if (finalScore <= Integer.parseInt(scores.get(i))) {
foundSpotForNewScore = true;
}
i++;
}
scores.add(i, String.valueOf(finalScore));
}
private void writeScores(List<String> scores) throws IOException {
FileWriter writer = new FileWriter("score.txt");
String outputScores = scores.toString();
outputScores = outputScores.replace("[", "");
outputScores = outputScores.replace("]", "");
writer.write(outputScores);
writer.close();
}
private void showLeaderBoard(List<String> scores) {
System.out.println("*** TOP 5 LEADERBOARD ***");
int i = 0;
while (i < 5 && i < scores.size()) {
System.out.println(scores.get(i));
i++;
}
System.out.println("*** TOP 5 LEADERBOARD ***");
}

Getting returned wrong values, but reading in fine in system? Java

I am trying to read in this input:
processcount 2 # Read 2 processes
runfor 15 # Run for 15 time units
use rr # Can be fcfs, sjf, or rr
quantum 2 # Time quantum – only if using rr
process name P1 arrival 3 burst 5
process name P2 arrival 0 burst 9
end
My job is to only parse in the values and not the words, and to keep out the comments (#).
Here is the main file:
public class main {
static String[] token = new String[10];
static List<Schedule> p;
public static void schedule()
{
for(Schedule c: p)
{
System.out.println("ProcessInfo: " + c.getProcess().processName);
System.out.println("count: " + c.getProcessCount());
System.out.println("quant: " + c.getQuantum());
System.out.println("runtime: " + c.getRunTime());
System.out.println("Type: " + c.getType());
}
}
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
// sc = new Scanner(new File("processes.in"));
p = new ArrayList<>();
while(sc.hasNextLine() && !sc.equals("end"))
{
token = sc.nextLine().replace(" ","-").replace("#", "-").split("-");
System.out.println(token[0].toString());
if(!token[0].startsWith("#") || !sc.nextLine().startsWith("end"))
{
Schedule s = new Schedule();
int pCount=0, runfor=0, quantum=0, arrival=0, burst=0;
String type = null, pName = null;
if(token[0].startsWith("processcount"))
{
s.setProcessCount(Integer.parseInt(token[1]));
System.out.println(Integer.parseInt(token[1] +""));
}
else if(token[0].startsWith("runfor"))
{
s.setRunTime(Integer.valueOf(token[1].toString()));
System.out.println(Integer.parseInt(token[1]) +"");
}
else if(token[0].startsWith("use"))
{
s.setType(token[1].toString());
System.out.println(token[1] +"");
}
else if(token[0].startsWith("quantum"))
{
s.setQuantum(Integer.valueOf(token[1].toString()));
System.out.println(token[1] + "");
}
else if(token[0].startsWith("process"))
{
Processes pl = new Processes();
pl.setProcessName(token[2]);
System.out.println(token[2]+ "");
pl.setArrivalTime(Integer.valueOf(token[4].toString()));
System.out.println(""+ Integer.valueOf(token[4]));
pl.setBurstTime(Integer.valueOf(token[6].toString()));
System.out.println("" + token[6]);
s.setProcess(pl);
// add info
p.add(s);
}
else if(token[0].startsWith("end"))
{
schedule();
}
}
}
}
}
Here is the Schedule:
public class Schedule {
int processCount;
int runTime;
String type;
int quantum;
Processes process;
public int getProcessCount() {
return processCount;
}
public void setProcessCount(int processCount) {
this.processCount = processCount;
}
public int getRunTime() {
return runTime;
}
public void setRunTime(int runTime) {
this.runTime = runTime;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getQuantum() {
return quantum;
}
public void setQuantum(int quantum) {
this.quantum = quantum;
}
public Processes getProcess() {
return process;
}
public void setProcess(Processes p) {
process = p;
}
}
Here is the Process:
public class Processes {
String processName;
int arrivalTime;
int burstTime;
public String getProcessName() {
return processName;
}
public void setProcessName(String processName) {
this.processName = processName;
}
public int getArrivalTime() {
return arrivalTime;
}
public void setArrivalTime(int arrivalTime) {
this.arrivalTime = arrivalTime;
}
public int getBurstTime() {
return burstTime;
}
public void setBurstTime(int burstTime) {
this.burstTime = burstTime;
}
}
Here is the output I am getting with my code:
ProcessInfo: P1
count: 0
quant: 0
runtime: 0
Type: null
ProcessInfo: P2
count: 0
quant: 0
runtime: 0
Type: null
why am I getting returned wrong results?
There's couple of issue here. You create a new schedule at each iteration of your while loop; you don't get all the relevant values of your current line before the new iteration plus you have couple of useless variables right after you create a new Schedule() which override the previously collected values.
Also, you use toString on a String element of your array which is meaningless. Personnaly I don't try not to use filters and you don't really need any for this. Always try to KISS(Keep It Simple Stupid)
Here's how I'll go about it without using filters.
public static void main (String args [])
{
// Will help us identify the key words
String current_token;
Scanner sc = new Scanner(System.in);
String input = sc.nextLine();
//Remove spaces at the beginning and end of the string
input = input.trim();
Schedule s = new Schedule();
// New source for the scanner
sc =new Scanner(input);
p = new ArrayList<>();
while(sc.hasNext())
{
current_token = sc.next();
if(current_token.equals("end"))
{schedule(); break;}
switch(current_token)
{
case "processcount":
s.setProcessCount(sc.nextInt());
System.out.println(s.getProcessCount()+ " ");
break;
case "runfor":
s.setRunTime(sc.nextInt());
System.out.println(s.getRuntime +" ");
case "use":
s.setType(sc.next());
System.out.println(s.getType() +" ");
break;
case "quantum":
s.setQuantum(sc.nextInt());
System.out.println(s.getQuantum + " ");
break;
case "process":
Processes pl = new Processes();
pl.setProcessName(sc.next());
System.out.println(pl.GetProcessName()+ " ");
pl.setArrivalTime(sc.nextInt());
System.out.println(" "+ pl.getArrivalTime());
pl.setBurstTime(sc.nextInt());
System.out.println(" " + pl.getBurstTime());
s.setProcess(pl);
// add info
p.add(s);
break;
default:
// the current_token is not what we are looking for
break;
}
}
}
You're having an issue because of the way you split the string. The way you have right now first replaces each space with a dash. For example, the string
"processcount 2 # a comment"
would become
"processcount-2---#-a-comment"
and then splitting that gives you an empty string between every pair of dashes, so you'll end up with
token = ["processcount", "2", "","", ... etc]
I suggest that you do this:
String str = (sc.nextLine().split("#"))[0]; //get the string before the pound sign
str = str.trim(); //remove the leading/trailing whitespace
token = str.split("\\s+"); //split the string by the whitespaces

Java Scanner issues, Notecard class

I am trying to make a program that is basically virtual notecards. Each notecard has a string for a question and an answer as well as a count for now many times it has been asked. I am using a scanner in many instances and I think i am using it incorrectly, and am not quite sure why. The program will let me answer the first 2 questions, tell me they are incorrect no matter what, and skip letting me answer the last one. Here is the notecard class:
public class Notecard {
public String ans;
public String q;
public int count;
public Notecard(String q, String ans) {
this.q = q;
this.ans = ans;
this.count = 0;
}
public Boolean answer(String effort) {
if (this.q.toUpperCase().equals(effort.toUpperCase())) {
System.out.println("Correct!");
return true;
} else {
System.out.println("Incorrect! Correct answer:" + this.ans);
count++;
return false;
}
}
public void clearCount() {
this.count = 0;
}
public String getQ() {
return this.q;
}
}
and here is my other file:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.Scanner;
public class CreateNotecard {
int trys;
public static void main(String[] args) {
System.out.println("Get ready to be quizzed \n\n");
ArrayList<Notecard> notecards = makeCards();
quiz(notecards);
}
static ArrayList<Notecard> makeCards() {
ArrayList<Notecard> notecards = new ArrayList<Notecard>();
try {
BufferedReader in = new BufferedReader(new FileReader(
"notecards.txt"));
String str;
str = in.readLine();
while ((str = in.readLine()) != null) {
String[] argg = str.split(",");
notecards.add(new Notecard(argg[0], argg[1]));
}
in.close();
} catch (IOException e) {
System.out.println("File Read Error");
}
return notecards;
}
static void quiz(ArrayList<Notecard> notecards) {
ArrayList<Notecard> backupList = notecards;
Scanner sc = new Scanner(System.in);
long seed = System.nanoTime();
Collections.shuffle(notecards, new Random(seed));
int total = notecards.size();
int correct = 0;
for (Notecard x : notecards) {
System.out.println(x.getQ());
String effort = sc.next();
Boolean nailedIt = x.answer(effort);
if (nailedIt) {
correct++;
}
}
System.out.println("Total Notecards: " + total + "\nTotal Correct: "
+ correct);
System.out.println("Accuracy: " + (correct / total));
System.out.println("Do you want to repeat? Put \"y\" or \"n\"");
String choice1 = sc.nextLine();
if (choice1.toUpperCase().equals("Y")) {
System.out.println("Use only cards missed or all? Type \"missed\" or \"all\"");
String choice2 = sc.nextLine();
if (choice2.toUpperCase().equals("MISSED")) {
quiz(notecards);
} else {
quiz(backupList);
}
} else {
return;
}
}
}
I have a text file which I am using for this program, it contains
19-9,10
square root of 4,2
capitol of Missouri,Jefferson City
Blastoise's 1st evolution,squirtle
and my output is
Get ready to be quizzed
square root of 4
2
Incorrect! Correct answer:2
capitol of Missouri
Jefferson City
Incorrect! Correct answer:Jefferson City
Blastoise's 1st evolution
Incorrect! Correct answer:squirtle
Total Notecards: 3
Total Correct: 0
Accuracy: 0
Do you want to repeat? Put "y" or "n"
You are comparing the wrong things:
public Boolean answer(String effort) {
if (this.q.toUpperCase().equals(effort.toUpperCase())) {
Should be
if (this.ans.toUpperCase().equals(effort.toUpperCase())) {
The problem is that the Scanner class is looking for a delimiter to create tokens with, which is by default whitespace. Since you enter "2", the Scanner.next() finds no delimiters, so no token.
For example, if you enter "Jefferson City", the Scanner found one delimiter, so two tokens. sc.next in that case would be "Jefferson" only (no "City", that's the next token).
Solution? Read the line from stdin and using sc.nextLine()

Java: Printing Arraylist to Output File?

EDIT: To test these cases, change sort and filter methods to the following:
EXAMPLE SORT METHOD:
public void sortTitle() {
Collections.sort(songs2, SongComparator.byTitle()); // now we have a sorted list
}
EXAMPLE FILTER METHOD (FOR STRING INPUT):
public void filterTitle(String s) {
int n = 0;
if (n == 0) {
n++;
for (Song song1 : songs2) {
if ((!(((song1.title).contains(s))))) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
}
EXAMPLE FILTER METHOD (FOR INT INPUT):
public void filterRank(Range r) {
int n = 0;
if (n == 0) {
n++;
for (Song song1 : songs2) {
if (song1.rank > (r.getMax()) || (song1.rank) < (r.getMin())) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
}
TEST CASES:
Input strings should be like the following examples:
sort:title
This input runs successfully until
the line System.setOut(out); in the main class, where it begins to print spaces and does not successfully print the collection. This may be because of a problem with the toString method in the SongCollection class.
artist:Paramore
or
title:Misery Business
This input runs successfully through the entire program (the program does not terminate because the while loop does not terminate), except instead of printing the collection, a blank space is printed.
ADDITIONAL DETAILS:
This question is a followup to a previous question I asked, since I have short time constraints on this project (it is due tomorrow).
The primary problem I am experiencing with this is that the program is failing to output correctly, even though the methods and code in the main for printing seems logically sound.
Printing arraylist into output file?
For some reason, it takes an extraordinary amount of time for the ArrayLists to be printed to the output file, usually 20-30 minutes. However, this only happens with the sort methods or the filterTitle or filterArtist methods (methods that concern String inputs).
When I run filterRank or filterYear, it runs perfectly fine.
When I print the song2 ArrayList directly from the filter methods, the only thing that is printed is [], which means the ArrayList is empty, but it shouldn't be? And the filterRank and filterYear methods still work regardless of this.
Somehow I think it's related, though.
Input file can be found here: http://staff.rentonschools.us/hhs/ap-comp-science/projects/download/agazillionsongs.txt?id=223098
Full code for compilation:
import java.io.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.Comparator;
import java.util.Scanner;
import java.util.StringTokenizer;
public class GazillionSongs {
public static void main(String[] args) throws FileNotFoundException, IOException {
System.out.println("Welcome to Java Song Collection!"); // greets the user
System.out
.println("This program sorts and filters large databases of popular songs."); // explains purpose of program
System.out
.println("This program is able to filter and sort by year, artist, title and rank.");
System.out
.println("Please enter a file that contains a database you wish to filter or sort. (i.e, alistofsongs.txt)"); // sample file = agazillionsongs.txt
Scanner fileInput = new Scanner(System.in); //Scanner which accepts filename
String filename = fileInput.nextLine();
File f = new File(filename); //creates file from input
/*error check for file here*/
Scanner fileScanner = new Scanner(f); //inputs data from file
ArrayList<Song> songs = new ArrayList<Song>();
while ((fileScanner.hasNextLine())) {
songs.add(Song.parse(fileScanner.nextLine()));
}
System.out
.println("Please select which commands you would like to use for the program.");
System.out
.println("Please format your command like the following example: year:<year(s)> rank:<rank(s)> artist:<artist> title:<title> sortBy:<field>");
System.out.println();
System.out.println("You may pick any number of commands you want.");
System.out
.println("For years and rank, you may select a range of years or ranks.");
System.out
.println("For artists and titles, you may enter a partial name or title.");
System.out.println("i.e, year:1983 rank:1");
Scanner input = new Scanner(System.in);
while (input.hasNextLine()) {
int n = 0;
SongCollection collection = new SongCollection(songs);
String inputType = input.nextLine();
String delims = "[ ]";
String[] tokens = inputType.split(delims);
for (int i = 0; i < tokens.length; i++) {
n = 0;
if (n == 0) {
if ((tokens[i]).contains("year:")) {
collection.filterYear(Range.parse(tokens[i]));
n = 1;
}// end of year loop
if ((tokens[i]).contains("rank:")) {
collection.filterRank(Range.parse(tokens[i]));
n = 1;
}// end of rank
if ((tokens[i]).contains("artist:")) {
collection.filterArtist(tokens[i]);
n = 1;
}// end of artist
if ((tokens[i]).contains("title:")) {
collection.filterTitle(tokens[i]);
n = 1;
}// end of title
if ((tokens[i]).contains("sort:")) {
if ((tokens[i]).contains("title")) {
collection.sortTitle();
n = 1;
}// end of sort title
if ((tokens[i]).contains("artist")) {
collection.sortArtist();
n = 1;
}// end of sort artist
if ((tokens[i]).contains("rank")) {
collection.sortRank();
n = 1;
}// end of sort rank
if ((tokens[i]).contains("year")) {
collection.sortYear();
n = 1;
}// end of sort year
}//end of sort
}// end of for loop
}// end of input.hasNextline loop
final PrintStream console = System.out; //saves original System.out
File outputFile = new File("output.txt"); //output file
PrintStream out = new PrintStream(new FileOutputStream(outputFile)); //new FileOutputStream
System.setOut(out); //changes where data will be printed
System.out.println(collection.toString());
System.setOut(console); //changes output to print back to console
Scanner outputFileScanner = new Scanner(outputFile); //inputs data from file
while ((outputFileScanner.hasNextLine())) { //while the file still has data
System.out.println(outputFileScanner.nextLine()); //print
}
outputFileScanner.close();
out.close();
}
}// end of main
}// end of class
class Song{
public enum Order {Year, Rank, Title, Artist}
public int year;
public int rank;
public String artist;
public String title;
public static Song parse(String s) {
Song instance = new Song();
StringTokenizer tokenizer = new StringTokenizer(s, "\t");
instance.year = Integer.parseInt(tokenizer.nextToken());
instance.rank = Integer.parseInt(tokenizer.nextToken());
instance.artist = (tokenizer.nextToken());
instance.title = (tokenizer.nextToken());
return instance;
}
public int getYear() {
return year;
}
public int getRank() {
return rank;
}
public String getArtist() {
return artist;
}
public String getTitle() {
return title;
}
public String toString() {
String output = "\n\nYear = " + year + "\nRank = " + rank + "\nArtist = "
+ artist + "\nTitle = " + title;
return output;
}
}
class Range {
private int min;
private int max;
public Range() {
System.out.println("Please wait.");
}
public static Range parse(String s) {
Range instance = new Range(); // instance is created here so object
// variables may be accessed
String field; // String to contain deleted part of user input
StringTokenizer tokenizer = new StringTokenizer(s, "-");
StringTokenizer tokenizer2 = new StringTokenizer(s, ":");// for separating "field:" from the
// other part of the String
if (s.contains(":")) { // this deletes the "field:" of the user input so
// it does not interfere with the parsing
field = (tokenizer2.nextToken());
s = s.replace(field, "");
s = s.replace(":", "");
}
if (s.contains("-")) {
instance.min = Integer.parseInt(tokenizer.nextToken());
instance.max = Integer.parseInt(tokenizer.nextToken());
} else if (!(s.contains("-"))) {
{
instance.min = Integer.parseInt(s);
instance.max = Integer.parseInt(s);
}
}
System.out.println("Range max = " + instance.max);
System.out.println("Range min = " + instance.min);
return instance;
}
public boolean contains(int n) {
if (n > min && n < max) { //if the number is contained in the range, method returns true.
return true;
} else if (n == min && n == max) {
return true;
} else {
return false;
}
}
public int getMin() {
return min;
}
public int getMax() {
return max;
}
}
class SongCollection {
ArrayList<Song> songs2;
ArrayList<Song> itemsToRemove = new ArrayList<Song>(); // second collection
// for items to
// remove
public SongCollection(ArrayList<Song> songs) { // constructor for SongCollection
System.out.println("Test");
this.songs2 = songs;
}
public void filterYear(Range r) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if (song1.year > (r.getMax()) || (song1.year) < (r.getMin())) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
public void filterRank(Range r) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if (song1.rank > (r.getMax()) || (song1.rank) < (r.getMin())) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
public void filterArtist(String s) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if ((!(((song1.artist).contains(s))))) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
public void filterTitle(String s) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if ((!(((song1.title).contains(s))))) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
public void sortTitle() {
Collections.sort(songs2, SongComparator.byTitle()); // now we have a sorted list
System.out.println(songs2);
}
public void sortRank() {
Collections.sort(songs2, SongComparator.byRank()); // now we have a sorted list
System.out.println(songs2);
}
public void sortArtist() {
Collections.sort(songs2, SongComparator.byArtist()); // now we have a sorted list
System.out.println(songs2);
}
public void sortYear() {
Collections.sort(songs2, SongComparator.byYear()); // now we have a sorted list
System.out.println(songs2);
}
public String toString() {
String result = "";
for (int i = 0; i < songs2.size(); i++) {
result += " " + songs2.get(i);
}
return result;
}
}
class SongComparator implements Comparator<Song> {
public enum Order{
YEAR_SORT, RANK_SORT, ARTIST_SORT, TITLE_SORT
}
private Order sortingBy;
public SongComparator(Order sortingBy){
this.sortingBy = sortingBy;
}
public static SongComparator byTitle() {
return new SongComparator(SongComparator.Order.TITLE_SORT);
}
public static SongComparator byYear() {
return new SongComparator(SongComparator.Order.YEAR_SORT);
}
public static SongComparator byArtist() {
return new SongComparator(SongComparator.Order.ARTIST_SORT);
}
public static SongComparator byRank() {
return new SongComparator(SongComparator.Order.RANK_SORT);
}
#Override
public int compare(Song song1, Song song2) {
switch (sortingBy) {
case YEAR_SORT:
return Integer.compare(song1.year, song2.year);
case RANK_SORT:
return Integer.compare(song1.rank, song2.rank);
case ARTIST_SORT:
return song1.artist.compareTo(song2.artist);
case TITLE_SORT:
return song1.title.compareTo(song2.title);
}
throw new RuntimeException(
"Practically unreachable code, can't be thrown");
}
}
I tried to run this code and it works fine and fast. I am using file you posted and as you can see, test value for searching is "year:1983 sort:title". I also simplified it by removing while-cycle and user-input filename and filter string, so anyone can easily reproduce it.
If you want to help, I need to know, how to reproduce that 20-30 minute outputing to file.
:
import java.io.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.Comparator;
import java.util.Scanner;
import java.util.StringTokenizer;
public class GazillionSongs {
public static void main(String[] args) throws FileNotFoundException, IOException {
Scanner input = new Scanner(System.in);
System.out.println("Welcome to Java Song Collection!"); // greets the user
System.out
.println("This program sorts and filters large databases of popular songs."); // explains purpose of program
System.out
.println("This program is able to filter and sort by year, artist, title and rank.");
System.out
.println("Please enter a file that contains a database you wish to filter or sort. (i.e, alistofsongs.txt)"); // sample file = agazillionsongs.txt
File f = new File("agazillionsongs.txt"); //creates file from input
/*error check for file here*/
Scanner fileScanner = new Scanner(f); //inputs data from file
List<Song> songs = new ArrayList<Song>();
while ((fileScanner.hasNextLine())) {
Song song = Song.parse(fileScanner.nextLine());
songs.add(song);
}
System.out
.println("Please select which commands you would like to use for the program.");
System.out
.println("Please format your command like the following example: year:<year(s)> rank:<rank(s)> artist:<artist> title:<title> sortBy:<field>");
System.out.println();
System.out.println("You may pick any number of commands you want.");
System.out
.println("For years and rank, you may select a range of years or ranks.");
System.out
.println("For artists and titles, you may enter a partial name or title.");
System.out.println("i.e, year:1983 rank:1");
int n = 0;
SongCollection collection = new SongCollection(songs);
String inputType = "year:1983 sort:title";
String delims = "[ ]";
String[] tokens = inputType.split(delims);
for (int i = 0; i < tokens.length; i++) {
n = 0;
if (n == 0) {
if ((tokens[i]).contains("year:")) {
collection.filterYear(Range.parse(tokens[i]));
n = 1;
}// end of year loop
if ((tokens[i]).contains("rank:")) {
collection.filterRank(Range.parse(tokens[i]));
n = 1;
}// end of rank
if ((tokens[i]).contains("artist:")) {
collection.filterArtist(tokens[i]);
n = 1;
}// end of artist
if ((tokens[i]).contains("title:")) {
collection.filterTitle(tokens[i]);
n = 1;
}// end of title
if ((tokens[i]).contains("sort:")) {
if ((tokens[i]).contains("title")) {
collection.sortTitle();
n = 1;
}// end of sort title
if ((tokens[i]).contains("artist")) {
collection.sortArtist();
n = 1;
}// end of sort artist
if ((tokens[i]).contains("rank")) {
collection.sortRank();
n = 1;
}// end of sort rank
if ((tokens[i]).contains("year")) {
collection.sortYear();
n = 1;
}// end of sort year
}//end of sort
}// end of for loop
}// end of input.hasNextline loop
final PrintStream console = System.out; //saves original System.out
File outputFile = new File("output.txt"); //output file
PrintStream out = new PrintStream(new FileOutputStream(outputFile)); //new FileOutputStream
System.setOut(out); //changes where data will be printed
System.out.println(collection.toString());
System.setOut(console); //changes output to print back to console
Scanner outputFileScanner = new Scanner(outputFile); //inputs data from file
while ((outputFileScanner.hasNextLine())) { //while the file still has data
System.out.println(outputFileScanner.nextLine()); //print
}
outputFileScanner.close();
out.close();
}
}// end of main
class Song {
public enum Order {
Year, Rank, Title, Artist
}
public int year;
public int rank;
public String artist;
public String title;
public static Song parse(String s) {
Song instance = new Song();
StringTokenizer tokenizer = new StringTokenizer(s, "\t");
instance.year = Integer.parseInt(tokenizer.nextToken());
instance.rank = Integer.parseInt(tokenizer.nextToken());
instance.artist = (tokenizer.nextToken());
instance.title = (tokenizer.nextToken());
return instance;
}
public int getYear() {
return year;
}
public int getRank() {
return rank;
}
public String getArtist() {
return artist;
}
public String getTitle() {
return title;
}
public String toString() {
String output = "\n\nYear = " + year + "\nRank = " + rank + "\nArtist = "
+ artist + "\nTitle = " + title;
return output;
}
}
class Range {
private int min;
private int max;
public Range() {
System.out.println("Please wait.");
}
public static Range parse(String s) {
Range instance = new Range(); // instance is created here so object
// variables may be accessed
String field; // String to contain deleted part of user input
StringTokenizer tokenizer = new StringTokenizer(s, "-");
StringTokenizer tokenizer2 = new StringTokenizer(s, ":");// for separating "field:" from the
// other part of the String
if (s.contains(":")) { // this deletes the "field:" of the user input so
// it does not interfere with the parsing
field = (tokenizer2.nextToken());
s = s.replace(field, "");
s = s.replace(":", "");
}
if (s.contains("-")) {
instance.min = Integer.parseInt(tokenizer.nextToken());
instance.max = Integer.parseInt(tokenizer.nextToken());
} else if (!(s.contains("-"))) {
{
instance.min = Integer.parseInt(s);
instance.max = Integer.parseInt(s);
}
}
System.out.println("Range max = " + instance.max);
System.out.println("Range min = " + instance.min);
return instance;
}
public boolean contains(int n) {
if (n > min && n < max) { //if the number is contained in the range, method returns true.
return true;
} else if (n == min && n == max) {
return true;
} else {
return false;
}
}
public int getMin() {
return min;
}
public int getMax() {
return max;
}
}
class SongCollection {
List<Song> songs2;
List<Song> itemsToRemove = new ArrayList<Song>(); // second collection
// for items to
// remove
public SongCollection(List<Song> songs) { // constructor for SongCollection
System.out.println("Test");
this.songs2 = songs;
}
public void filterYear(Range r) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if (song1.year > (r.getMax()) || (song1.year) < (r.getMin())) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
public void filterRank(Range r) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if (song1.rank > (r.getMax()) || (song1.rank) < (r.getMin())) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
public void filterArtist(String s) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if ((!(((song1.artist).contains(s))))) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
public void filterTitle(String s) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if ((!(((song1.title).contains(s))))) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
public void sortTitle() {
Collections.sort(songs2, SongComparator.byTitle()); // now we have a sorted list
System.out.println(songs2);
}
public void sortRank() {
Collections.sort(songs2, SongComparator.byRank()); // now we have a sorted list
System.out.println(songs2);
}
public void sortArtist() {
Collections.sort(songs2, SongComparator.byArtist()); // now we have a sorted list
System.out.println(songs2);
}
public void sortYear() {
Collections.sort(songs2, SongComparator.byYear()); // now we have a sorted list
System.out.println(songs2);
}
public String toString() {
String result = "";
for (int i = 0; i < songs2.size(); i++) {
result += " " + songs2.get(i);
}
return result;
}
}
class SongComparator implements Comparator<Song> {
public enum Order {
YEAR_SORT, RANK_SORT, ARTIST_SORT, TITLE_SORT
}
private Order sortingBy;
public SongComparator(Order sortingBy) {
this.sortingBy = sortingBy;
}
public static SongComparator byTitle() {
return new SongComparator(SongComparator.Order.TITLE_SORT);
}
public static SongComparator byYear() {
return new SongComparator(SongComparator.Order.YEAR_SORT);
}
public static SongComparator byArtist() {
return new SongComparator(SongComparator.Order.ARTIST_SORT);
}
public static SongComparator byRank() {
return new SongComparator(SongComparator.Order.RANK_SORT);
}
#Override
public int compare(Song song1, Song song2) {
switch (sortingBy) {
case YEAR_SORT:
return Integer.compare(song1.year, song2.year);
case RANK_SORT:
return Integer.compare(song1.rank, song2.rank);
case ARTIST_SORT:
return song1.artist.compareTo(song2.artist);
case TITLE_SORT:
return song1.title.compareTo(song2.title);
}
throw new RuntimeException(
"Practically unreachable code, can't be thrown");
}
}
EDIT :
Question:
title:Misery Business
This input runs successfully through the entire program (the program does not terminate because the while loop does not terminate), except instead of printing the collection, a blank space is printed.
Yes, because in your method, you are testing, if it contains title:Misery Business not Misery Business.
First of all, you cant use that tokenizer for anything, that contains space. But for one-word only, you can change it as following :
Tested and working for title:Misery :
public void filterTitle(String s) {
int n = 0;
s = s.split(":")[1];
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if (song1.title.contains(s) == false) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}

Categories

Resources