How to write a method that prints out a histogram? - java

I have to write this program for lab. I have to basically illustrate exactly what a hashmap is (keys and values) and the basic operations of declaration, .add(), .get(), and how to get the keys and values from the map. You will then apply this to the frequency histogram problem using the woodchucks.txt input file. I've done all this but I'm stuck on how to write my method that prints the histogram. Can someone please help me out?
import java.io.*;
import java.util.*;
public class Lab8
{
public static void main(String args[]) throws Exception
{
BufferedReader infile = new BufferedReader(new FileReader(args[0]));
HashMap<String,Integer> histogram = new HashMap<String,Integer>();
String word;
while ( (word = infile.ready()) != null )
{
if(histogram.get(word)==null)
histogram.put(word,1);
else
histogram.put(word, histogram.get(word)+1);
}
// YOUR CODE HERE
infile.close();
printHistogram( histogram );
} // END MAIN
// YOU FILL IN THIS METHOD
// READ PROBLEM SPECIFICATION TO SEE WHAT IS THE 80% vs 100% CREDIT SOLUTION
private static void printHistogram( HashMap<String,Integer> hm )
{
// YOU CODE HERE
}
} // END LAB8 CLASS
Would I print the histogram like this?
for ( int i = 0; i < histogram.length; i++ )
{
output += "\n" + i + "\t" + histogram[ i ] + "\t";
for ( int j = 1; j <= histogram[ i ]; j++ )

So if i'll be doing this, i would start from creating two classes, one where i could hold word and number occurrences such as my HistogramItem
public class HistogramItem implements Comparable<HistogramItem> {
#Override
public String toString() {
return "HistogramItem [word=" + word + ", occurence=" + occurence
+ "]";
}
public int getOccurence() {
return occurence;
}
public void updateOccurence() {
this.occurence++;
}
public String getWord() {
return word;
}
public HistogramItem(String word) {
super();
this.word = word;
}
private final String word;
private int occurence = 0;
#Override
public int compareTo(HistogramItem o) {
if (occurence == o.occurence) {
return word.compareTo(o.word);
}
return o.occurence-occurence;
}
}
and other one which will be my actual histogram
public class Histogram {
private Map<String, HistogramItem> map = new HashMap<>();
private List<HistogramItem> list = new ArrayList<>();
public void addWord(String word) {
HistogramItem item = map.get(word);
if (item == null) {
item = new HistogramItem(word);
map.put(word, item);
list.add(item);
}
item.updateOccurence();
}
public List<HistogramItem> getList() {
Collections.sort(list);
return list;
}
}
i'm using two collections, hashmap, because search for entry is much quicker than in list, but list is much easier to sort, list can be created and sorted when requested
How this fits your original excercise? Simple
public static void main(String args[]) throws Exception
{
BufferedReader infile = new BufferedReader(new FileReader(args[0]));
Histogram histogram = new Histogram();
String word;
while ( (word = infile.ready()) != null )
{
histogram.addWord(w);
}
// YOUR CODE HERE
infile.close();
// Below line prints histogram, can be placed in printHistogram method
for (HistogramItem item : histogram.getList()) {
System.out.println(item.toString());
}
} // END MAIN

I figured it out and this is the answer...
import java.io.*;
import java.util.*;
public class Lab8
{
public static void main(String args[]) throws Exception
{
BufferedReader infile = new BufferedReader(new FileReader(args[0]));
HashMap<String,Integer> histogram = new HashMap<String,Integer>();
String word;
while ((infile.ready()))
{
word = infile.readLine();
if(histogram.get(word)== null) //if the word your currently on is not duplicated
{
histogram.put(word,1);
}
else
{
histogram.put(word, histogram.get(word)+1);
}
}
// YOUR CODE HERE
infile.close();
printHistogram( histogram );
} // END MAIN
// YOU FILL IN THIS METHOD
// READ PROBLEM SPECIFICATION TO SEE WHAT IS THE 80% vs 100% CREDIT SOLUTION
private static void printHistogram( HashMap<String,Integer> hm )
{
List <String> keys = new ArrayList<String> (hm.keySet());
Collections.sort(keys);
for (String key: keys)
{
System.out.println(key + "\t" + hm.get(key));
}
}
}// END LAB8 CLASS

Related

Difficulty reversing a linked list alphabetically

I'm having trouble reversing a LinkedList. In other words, I need them sorted in z-a order (in contrast to a-z). I've tried Collections.reverse but is not coming into effect? I have the following:
import java.io.*;
import java.util.*;
public class pa9Driver {
//create two list
//1st List is of type word class
//2nd list is of type Anagram_Family
public static List<Word> words = new LinkedList<Word>();
public static List<AnagramFamily> familyList = new LinkedList<AnagramFamily>();
//a main method for driver class
public static void main(String[] args) {
//call the generate method to read word from the file
generate_WordList();
//sort the word list
Collections.sort(words);
//generate the anagram family for the word
generate_FamilyList();
//sort the anagram family list
Collections.sort(familyList, new anagramFamilyComparator());
//reverse the anagram family list
Collections.reverse(familyList);
topFive();
}//main ends
public static void topFive() {
int i;
for(i = 0; i < 15; i++) {
System.out.print(familyList.get(i).getCanonicalForm1() + ", ");
System.out.print(familyList.get(i).getSize() + ": ");
System.out.println(familyList.get(i));
}
}
//method that read word
public static void generate_WordList() {
File inFile12=new File("words.txt");
Scanner fileRead1=null;
try {
fileRead1 = new Scanner(inFile12);
} catch (Exception exe) {
exe.printStackTrace();
System.exit(0);
}
//until the file has words read the words
while(fileRead1.hasNext()) {
words.add(new Word(fileRead1.next()));
}
}
//generate the anagram and add it to the current family
public static void generate_FamilyList() {
Iterator<Word> readWord1 = words.iterator();
Word previousWord1 = words.get(0);
familyList.add(new AnagramFamily());
int index1 = 0;
while(readWord1.hasNext()) {
Word currentWord1 = readWord1.next();
if(currentWord1.getCanonicalForm1().equals(previousWord1
.getCanonicalForm1())) {
familyList.get(index1).add(currentWord1);
} else {
index1++;
familyList.add(new AnagramFamily());
familyList.get(index1).add(currentWord1);
}
previousWord1 = currentWord1;
}
}
}
For convenience sake, I'll only show the first few lines of code that I have and that is expected.
Currently:
[apers, apres, asper, pares, parse, pears, prase, presa, rapes, reaps, spare, spear]
[alerts, alters, artels, estral, laster, ratels, salter, slater, staler, stelar, talers]
Expected:
[spear, spare, reaps, rapes, presa, prase, pears, parse, pares, asper, apres, apers]
[talers, stelar, staler, slater, salter, ratels, laster, estral, artels, alters, alerts]
Try:
Collections.sort(familyList, Comparator.reverseOrder());
Alternatively, you can do:
Collections.sort(familyList, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
//Print list in reverse order
for(String st : familyList){
System.out.println(st);
}
Seeing your code, it seems AnagramFamily is a kind of List, which you are not sorting.
You need to sort the AnagramFamily (List of String) with a StringComparator for getting your desired output.
I think you can use compareTo for this action no ? compareTo from Comparable

Breakpoint errors in javaeclipse

Good evening everyone. I'm working on a piece of homework and I finally have it nearly complete. Currently, the only thing stopping compilation is a breakpoint error at line 42. Eclipse tells me that it is the variable "list" being uninitialized, however, i cant find where or why this is happening.
The program is for a homework assignment in beginning java. It is designed to import a list of names from a text file called names.txt, then be able to sort through them in an interface, and while the menu is yet to be added, I want to get compiled and make sure its working before I go changing things again.
import java.util.*;
import java.io.*;
public class Name {
private String givenName;
private int[] ranks = new int[11];
public static void main( String[] args ) {
List<Name> list = new ArrayList<Name>();
loadFile();
System.out.println( list.get( 0 ).getPop( 0 ) );
}
private static void loadFile() {
Scanner inputStream = null;
String fileName = "names.txt";
try {
inputStream = new Scanner( new File( fileName ) );
}
catch (FileNotFoundException e) {
System.out.println( "Error opening file named: " + fileName );
System.out.println( "Exiting..." );
}
while ( inputStream.hasNextLine() ) {
String line = inputStream.nextLine();
String[] tokens = new String[0];
String givenName = tokens[0];
int[] numList = new int[tokens.length - 1];
for ( int i = 1; i < tokens.length; i++ ) {
numList[i - 1] = Integer.parseInt( tokens[i].trim() );
}
list.add( new Name( givenName, numList ) );
}
}
// here we get the name for the
public Name(String name, int[] popularityRanks) {
givenName = name;
for ( int i = 0; i < 11; i++ ) {
ranks[i] = popularityRanks[i];
}
}
public String getName() {
return givenName;
}
public int getPop( int decade ) {
if ( decade >= 1 && decade <= 11 ) {
return ranks[decade];
}
else {
return -1;
}
}
public String getHistoLine( int decade ) {
String histoLine = ranks[decade] + ": ";
return histoLine;
}
public String getHistogram() {
String histogram = "";
for ( int i = 0; i < 11; i++ ) {
histogram += ranks[i] + ": " + this.getHistoLine( i ) + "\n";
}
return histogram;
}
}
In addition, I used lists to configure the variables, but now i am deeply regretting it as I feel far more comfortable with just multi-dimensional arrays. As this is homework related, I completely understand if no one wants to help me fix this second part and give me some code to change the lists to arrays.
I'm burnt out and just want it to compile at this point. Any pointers on where to go from here?
Your list declaration/initialization is in the main and you are trying to access it from loadFile method.
Just move you List<Name> list = new ArrayList<Name>(); as a class variable(put it right above the main) and your code should compile.
Eg:
public class Name {
private String givenName;
private int[] ranks = new int[11];
static List<Name> list = new ArrayList<Name>();
public static void main( String[] args ) {
loadFile();
......
Your list is not visible to the point your are going to add a Name object. Its better to pass the list as a reference to the loadFile() method, As like follows
loadFile(list); // Method call from the main().
And Load file
private static void loadFile(List list) {
// Your code
}
I've restructured your code fixing the scopes and the object definition. If your individual logic is correct(which I haven't really checked), you should get your desired output).
What you seem to have mixed up is the object and the calling client. The Name private class is a private object which is being instantiated in the main method. Subsequently the public methods of the Name object is being called upon.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Solution {
private static class Name{
private final int items = 11;
private String givenName;
private int[] ranks;
//Constructor
public Name(String name, int[] popularityRanks) {
givenName = name;
ranks = new int[items];
for (int i = 0; i < items; i++) {
ranks[i] = popularityRanks[i];
}
}
public String getName() {
return givenName;
}
public int getPop(int decade) {
if (decade >= 1 && decade <= items) {
return ranks[decade];
} else {
return -1;
}
}
public String getHistoLine(int decade) {
String histoLine = ranks[decade] + ": ";
return histoLine;
}
public String getHistogram() {
String histogram = "";
for (int i = 0; i < 11; i++) {
histogram += ranks[i] + ": " + this.getHistoLine(i) + "\n";
}
return histogram;
}
}
public static void main(String[] args) {
List<Name> list = loadFile();
System.out.println(list.get(0).getPop(0));
}
private static List<Name> loadFile() {
List<Name> list = new ArrayList<>();
Scanner inputStream = null;
String fileName = "names.txt";
try {
inputStream = new Scanner(new File(fileName));
} catch (FileNotFoundException e) {
System.out.println("Error opening file named: " + fileName);
System.out.println("Exiting...");
}
while (inputStream.hasNextLine()) {
String line = inputStream.nextLine();
String[] tokens = new String[0];
String givenName = tokens[0];
int[] numList = new int[tokens.length - 1];
for (int i = 1; i < tokens.length; i++) {
numList[i - 1] = Integer.parseInt(tokens[i].trim());
}
list.add(new Name(givenName, numList));
}
return list;
}
}
First of all, ill advise you declare your list outside main,
Second, you want to populate the list before calling getPop.
look where you have:
System.out.println(list.get(0).getPop(0));
At this point list.get(0) returns null since the list hasn't been populated yet...and from your code getPop(0) will return -1, so the line above basically doesn't mean anything at that point.
And as for converting the list to arrays to make it "multidimensional"....
First lists can also be "multidimensional", if u know how to declare them...e.g
List> list = new ArrayList();
is a 2d array list.
Second generic lists like the one above are way flexible and have huge advantages over arrays, for example they can be dynamically modified; you can change their size at runtime unlike arrays.
With that said, if you want to convert a list to an array you need the type of the list and it's size and then it's easy using the toArray() method...like this:
String[] array = list.toArray(new String[list.size()]);

How to randomly choose a word from text and also reverse the same word when chosen

I would like to choose a word from a text file. Print that word and also print the same word in reverse. When I run the code, I have the output below. I just need to print the same word in reverse. But when I call the reverse method in the main function nothing prints.
Below is my code:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.Scanner;
public class SortingInput {
private static Scanner file;
private static ArrayList<String> words = new ArrayList<String>();
private static void openFile(){
try {
file = new Scanner(new File("word-file.txt"));
} catch (FileNotFoundException e) {
System.out.println("File Not Found.");
} catch (Exception e) {
e.printStackTrace();
System.out.println("IOEXCEPION");
}
}
public void closeFile(){
file.close();
}
private static void randomFile() {
Random r = new Random();
while(file.hasNextLine()){
words.add(file.nextLine());
}
String randomWord = words.get(r.nextInt(words.size()));
Collections.shuffle(words);
System.out.println(randomWord);
}
private static void reverse(ArrayList<String> array){
for(int i = 0; i < array.size(); i++) {
String element = array.get(i);
String setter = " ";
for(int k = 0; k < element.length(); k++){
char temp = element.charAt(element.length()- k - 1);
setter += temp;
}
array.set(i, setter);
}
}
public static void main(String[] args) {
openFile();
System.out.print("Before: ");
randomFile();
System.out.print("After: ");
reverse(words);**
}
}
You don't need to reverse the whole ArrayList of strings.
Remove private static void reverse(ArrayList<String> array) method, make randomFile()return a String which will be reversed. StringBuffer and StringBuilder classes have this reverse() method for reversing strings.
I also suggest you rename randomFile() to randomWord() since you're randomizing words not files.
randomWord():
private static String randomWord() {
Random r = new Random();
while(file.hasNextLine()){
words.add(file.nextLine());
}
String randomWord = words.get(r.nextInt(words.size()));
// Collections.shuffle(words); -> this is not needed since randomWord is already produced.
return randomWord;
}
main():
public static void main(String[] args) {
openFile();
String random = randomWord();
System.out.println("Before: " + random);
System.out.print("After: " + new StringBuilder(random).reverse() );
}
Sample output:
Before: hallow
After: wollah
The code would be much shorter if you use FileUtils from Apache Common IO and StringBuilder. An example is:
public static void main( String[] args )
{
File file = new File( "word-file.txt" );
try
{
List<String> lines = FileUtils.readLines( file );
Random random=new Random();
String before=lines.get(random.nextInt(lines.size()));
System.out.println("Before:"+before);
System.out.println("After:"+ new StringBuilder(before).reverse());
}
catch( IOException e )
{
e.printStackTrace();
}
}

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);
}

Extending my program to report frequency of word in list and its line number?

I've gotten my Java code below to this point. Now what I'm attempting to do is add to it so that it can report, for each word in the list, its frequency (number of times it exists) along with the line numbers where the word occurs.
CODE:
// Concordance
import java.util.*;
// A concordance is a listing of words from a text, with each word being followed the line/page numbers on which the word appears.
public class Concordance
{
private Dictionary dict = new Hashtable();
private boolean allowDupl = true;
public Concordance (boolean allowDupl )
{
this.allowDupl = allowDupl;
} // end Concordance()
public Concordance ( ) { this(true); }
public void enterWord (Object word, Integer line)
{
Vector set = (Vector) dict.get(word);
if (set == null) // word not in dictionary
{
set = new Vector( );
dict.put(word, set); // enter word and empty Vector
}
if (allowDupl || !set.contains(line))
{
set.addElement(line);
}
} // end enterWord()
public Enumeration keys( )
{
return dict.keys( );
} // end keys()
public Enumeration getNumbers (Object word)
{
return ((Vector)dict.get(word)).elements( );
} // end getNumbers()
} // end class Concordance
This is something I've been dabbling with, but Java is not at all my strong-language. Can anyone offer advice on how to proceed?
EDIT:
I've updated my code with the below. For those more familiar with Java, does this look correct?
CODE:
// Concordance
import java.util.*;
// A concordance is a listing of words from a text, with each word being followed the line/page numbers on which the word appears.
public class Concordance
{
private Dictionary dict = new Hashtable();
private boolean allowDupl = true;
public Concordance (boolean allowDupl )
{
this.allowDupl = allowDupl;
} // end Concordance()
public Concordance ( ) { this(true); }
public void enterWord (Object word, Integer line)
{
Vector set = (Vector) dict.get(word);
if (set == null) // word not in dictionary
{
set = new Vector( );
dict.put(word, set); // enter word and empty Vector
}
if (allowDupl || !set.contains(line))
{
set.addElement(line);
}
} // end enterWord()
public void generateOutput(PrintStream output)
{
Enumeration e = dict.keys();
while (e.hasMoreElements())
{
String word = (String) e.nextElement();
Vector set = (Vector) dict.get(word);
output.print(word + ": ");
Enumeration f = set.elements();
}
while (f.hasMoreElements())
{
output.print(f.nextElement() + " ");
output.println("");
}
}
public Enumeration keys( )
{
return dict.keys( );
} // end keys()
public Enumeration getNumbers (Object word)
{
return ((Vector)dict.get(word)).elements( );
} // end getNumbers()
} // end class Concordance
Create a Class DictionaryEntry that has all the attributes you need and then put that into your Dictionary instead of just a set of int for the line numbers.

Categories

Resources