1. Not finding help here? Sign up for a free 30min tutor trial with Chegg Tutors
    Dismiss Notice
Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Trying to override the hashcode()

  1. Feb 3, 2013 #1

    Zondrina

    User Avatar
    Homework Helper

    1. The problem statement, all variables and given/known data

    I'm trying to override the hashcode(), equals() and compareTo() methods in a class.

    2. Relevant equations

    Java.

    3. The attempt at a solution

    Here's the code :

    Code (Text):
    package data_cleaner;

    import java.util.*;

    public class SongEntry implements Comparable<SongEntry> {

        private String studentNumber;
        private String bookCode;
        private int pageNumber;
        private String songTitle;

        public SongEntry(String studentNumber, String bookCode, int pageNumber, String songTitle) {
            this.studentNumber = studentNumber;
            this.bookCode = bookCode;
            this.pageNumber = pageNumber;
            this.songTitle = songTitle;
        }
       
        /*Getters and setters*/
        public String getSongTitle() { return songTitle; }
        public String getStudentNumber() { return studentNumber; }
        public String getBookCode() { return bookCode; }
        public int getPageNumber() { return pageNumber; }
        public void setSongTitle(String newSongTitle) { songTitle = newSongTitle; }

        @Override
        /*Returns a String representation of a SongEntry*/
        public String toString() {
            return (studentNumber + " " + bookCode + " " + pageNumber + " " + songTitle);
        }

        @Override
        /*Compares two songs to see if they are equal to each other by comparing song titles, book code and page numbers*/
        public boolean equals(Object obj) {
            if (!(obj instanceof SongEntry))
                return false;
            return(getBookCode().equals(((SongEntry)obj).getBookCode()) && getPageNumber() == ((SongEntry)obj).getPageNumber() && getSongTitle().equals( ((SongEntry)obj).getSongTitle()));
        }

        @Override
        /*Retrieve the name of the song and loop through the name adding on (i+1)*ASCIIVALUE of each char
        to the hashvalue which will be returned*/

        public int hashCode() {
            int hashValue = 0;
            for(int i=0;i<getSongTitle().length();i++)
                hashValue += ((int)getSongTitle().charAt(i))*(Integer.parseInt(getStudentNumber()))*(getPageNumber());
            return hashValue;
        }
       
        @Override
        /*Recall x.equals(y) iff x.hashcode() == y.hashcode(). Also, x.equals(y) iff x.compareTo(y) == 0.
        Hence x.compareTo(y) == 0 iff x.hashcode() - y.hashcode() == 0.
    This implies we can subtract the hashcode of y from x to compare each songEntry and return it.*/
        public int compareTo(SongEntry aSongEntry) {
            return (hashCode() - aSongEntry.hashCode());
        }
    }

     
    I don't believe the methods I wrote are correct? I believe there are rules which I've missed, but I cannot see where I've made a mistake?
     
    Last edited by a moderator: Feb 4, 2013
  2. jcsd
  3. Feb 3, 2013 #2

    CompuChip

    User Avatar
    Science Advisor
    Homework Helper

    Re: Hashsets

    I didn't look in too much detail, but I propose you look for the documentation of .equals() and .hashCode() again. They can be a bit intimidating, but if you are writing such code it will be useful to read it thoroughly and understand it. And you can use it as a sort of checklist to make sure you satisfy the requirements.

    Two of the flaws that I noticed first were that hashCode() can change during the lifetime of the object, and I think if you want to stick it in hashmaps that's not such a good idea. Since the student number, book number and page number have no setters, I would use one of those instead (or a combination of them, of course).

    The second thing is that you wrote " x.equals(y) iff x.hashcode() == y.hashcode()". The "only if" is true (two equal objects have the same hash code) but the "if" is not. Two non-equal objects can perfectly well share a hash code, although for efficiency in storing data in hashmaps it is recommended that they are spread out as uniformly through the allowed range of hash codes as possible (though this is the least critical requirement, I think, because although it can degrade your maps performance to linear search of a single list, at least it it won't break them; since it is often hard to satisfy all requirements for a general type this is the most disregarded item.)
     
  4. Feb 3, 2013 #3

    Zondrina

    User Avatar
    Homework Helper

    Re: Hashsets

    I'm not using hashmaps, I'm using hashset.

    The JAVA Api and examples are not clear at all about the Collection interface. I've read them 8 times at least.

    I'll be more clear about my objective, perhaps it would make things easier to communicate.

    I want to be able to load data from a text file ( which I've done using a BufferedReader ) which is in the format :

    studentnumber,bookcode,page#,songname

    Example : 10101010,AAAA,999,"Hello"
    Example : 10000001,BBBB,000,That's, cool

    line by line. Each line is one after the other in the text file so I can use readLine() to read it into a String or StringBuilder.

    Then I want to be able to format the data ( The songname portion in particular since everything else doesn't matter ) and create a SongEntry object using the constructor.

    I'll then store those SongEntry objects into my hashset and use PrintWriter to output this newly formatted data to a new text file.

    Here's my code from my other class if it helps ( main at the bottom ) :

    Code (Text):
    package data_cleaner;

    import java.util.*;
    import java.io.*;

    public class DataCleaner {

        //student number to identify student
        private String studentNumber = "100804018";
        //set to hold song entries
        private HashSet<SongEntry> songDataSet = new HashSet<SongEntry>();
       
        //default constructor
        public DataCleaner() {
        }

        //Getters and setters
        public HashSet<SongEntry> getSongDataSet() { return songDataSet; }
        public String getStudentNumber() { return studentNumber; }
       
        //Load data, clean it and then put it into the hashset
        public void loadData(String dataFile) {
            int numberOfSongsRead = 0;

            try {
                //Load the text file
                BufferedReader file = new BufferedReader(new FileReader(dataFile));
               
                //Read each line until EOF and clean it up
                while(file.ready()){
                    StringBuilder songData = new StringBuilder((file.readLine()).trim());
                    numberOfSongsRead++;
                    boolean isThe = false;
                    int counter = 0;
               
                    //Eliminates unnecessary commas
                    for(int i=0;i<songData.length();i++) {
                        if(songData.charAt(i) == ',' && counter < 3)
                            counter++;
                        else if(songData.charAt(i) == ',')
                            songData.setCharAt(i, ' ');
                    }

                    //Split the newly formatted data for ease of manipulation and reset the string builder for usage
                    String[] splitSongData = (songData.toString()).split(",");
                    splitSongData[3] = splitSongData[3].toLowerCase();
                    songData = new StringBuilder();
                    songData.append('"');
                   
                    //Loop through each song name. Clean it and put it inside of the hashset
                    for(int i=0;i<splitSongData[3].length();i++) {

                        //Check for the word 'the' in any form at the start of a song name.
                        if(i<2)
                            if(splitSongData[3].charAt(i) == 'T' || splitSongData[3].charAt(i) == 't')
                                if( (i+1 < splitSongData[3].length()) && (splitSongData[3].charAt(i+1) == 'H' || splitSongData[3].charAt(i+1) == 'h') )
                                    if( ( i+2 < splitSongData[3].length() ) && ( splitSongData[3].charAt(i+2) == 'E' || splitSongData[3].charAt(i+2) == 'e' ) )
                                        isThe = true;
                   
                        //These next two ifs will handle capitalization at the start of a song name
                        if(i==0 && Character.isLowerCase(splitSongData[3].charAt(i))) {
                            songData.append(Character.toUpperCase(splitSongData[3].charAt(i)));
                            continue;
                        }
                           
                        if(i<2 && Character.isLowerCase(splitSongData[3].charAt(i)))
                            if(splitSongData[3].charAt(i-1) == '"' || splitSongData[3].charAt(i-1) == '(') {
                                songData.append(Character.toUpperCase(splitSongData[3].charAt(i)));
                                continue;
                            }
                       
                        //These next two ifs will handle capitalization mid-name as well as default appending behaviour
                        if(Character.isLowerCase(splitSongData[3].charAt(i)) && Character.isWhitespace(splitSongData[3].charAt(i-1))) {
                            songData.append(Character.toUpperCase(splitSongData[3].charAt(i)));
                            continue;
                        }
                           
                        if(splitSongData[3].charAt(i) != '"')
                            songData.append(splitSongData[3].charAt(i));
                    }
                       
                    //Some minor touch ups as per formatting
                    if(isThe)
                        songData.append(", The\"");
                    else
                        songData.append('"');
                   
                    getSongDataSet().add(new SongEntry(splitSongData[0], splitSongData[1], (int)(Integer.parseInt(splitSongData[2])), songData.toString()));
                }  
            }
           
            catch (FileNotFoundException e) {  
                System.out.println("Error: Cannot find file");  
            }
            catch (IOException e) {  
                System.out.println("Error: Cannot read from file");  
            }
           
            System.out.println(getSongDataSet().size());
            //for(SongEntry s : getSongDataSet())
                //System.out.println(s);
           
            System.out.println("A data file has been read! Ammount of songs read from data file : " + numberOfSongsRead);

        }

        public void cleanData() {
            TreeSet<SongEntry> alphaTree = new TreeSet<SongEntry>();
            alphaTree.addAll(getSongDataSet());
            //for(SongEntry s : alphaTree)
                //System.out.println(s);
        }

        public void exportData(String toFileName) {
            try {
                PrintWriter aFile = new PrintWriter(new FileWriter("outputdata.txt"));
                for(SongEntry s : getSongDataSet())
                    aFile.println(s.toString());
                aFile.close();
            }
            catch (FileNotFoundException e) {  
                System.out.println("Error: Cannot find file");  
            }
            catch (IOException e) {  
                System.out.println("Error: Cannot read from file");  
            }
        }
       
        public void exportMyData(String toFileName) {
            try {
                PrintWriter aFile = new PrintWriter(new FileWriter("myoutputdata.txt"));
                for(SongEntry s : getSongDataSet()) {
                    if(s.getStudentNumber().equals(studentNumber))
                        aFile.println(s.toString());
                }
                aFile.close();
            }
            catch (FileNotFoundException e) {  
                System.out.println("Error: Cannot find file");  
            }
            catch (IOException e) {  
                System.out.println("Error: Cannot read from file");  
            }    
        }
       
        public void resetData() {
            //reset all gathered data
            songDataSet.clear();
        }

        public void runDataCleaner() {
            //Perform the steps of the data cleaner exercise
            System.out.println("Running Data Cleaner");

            //Step 1: Read master data into a set
            loadData("fakebookdata.txt");
           
            //Step 2: Read Student contribution file into set
            loadData("mydata.txt");
           
            //Step 3: Do additional cleaning not done during loading
            cleanData();
           
            //Step 4: Export sorted and cleaned data
            exportData("outputdata.txt");
           
            //Step 5: Export only the data I contributed
            exportMyData("myoutputdata.txt");
        }

        public static void main(String[] args) {
            System.out.println("Starting Fake Book Data Cleaner");
            DataCleaner app = new DataCleaner();
            app.runDataCleaner();
        }
    }
    Also I believe I'm supposed to be able to use the hashcode(), equals() and compareTo() to my advantage to reduce the ammount of code I needed?
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook




Similar Discussions: Trying to override the hashcode()
Loading...