Autocomplete byReverseWeightOrder comparator issue

1k views Asked by At

I have been working on this problem for several hours now and I just cannot figure out what I am doing wrong here. Could anyone help point me in the right direction?

I was asked to write an Autocomplete program and I've completed everything except for this one method I cannot get working. Each term has: 1. String query and 2. long weight.

Here is the method:

public static Comparator<Term> byReverseWeightOrder() {
    return new Comparator<Term>() { // LINE CAUSING PROBLEM
        public int compare(Term t1, Term t2) {
            if (t1.weight > t2.weight) { // LINE CAUSING PROBLEM
                return -1;
            } else if (t1.weight == t2.weight) {
                return 0;
            } else {
                return 1;
            }
        } 
    };   
}

My problem is that no matter how I mess with the method I always result in a NullPointerException(). Which, it points to this method (byReverseWeightOrder) as well as these two statements.

Arrays.sort(matches, Term.byReverseWeightOrder());
Term[] results = autocomplete.allMatches(prefix);

Here is the rest of the code if it can be found helpful:

Term

    import java.util.Comparator;

public class Term implements Comparable<Term> {
   public String query;
   public long weight;

   public Term(String query, long weight) {
      if (query == null) {
         throw new java.lang.NullPointerException("Query cannot be null");
      } 
      if (weight < 0) {
         throw new java.lang.IllegalArgumentException("Weight cannot be negative");
      }

      this.query = query;
      this.weight = weight;
   }

   public static Comparator<Term> byReverseWeightOrder() {
      return new Comparator<Term>() {
            public int compare(Term t1, Term t2) {
               if (t1.weight > t2.weight) {
                  return -1;
               } else if (t1.weight == t2.weight) {
                  return 0;
               } else {
                  return 1;
               }
            }
         };
   }

   public static Comparator<Term> byPrefixOrder(int r) {
      if (r < 0) {
         throw new java.lang.IllegalArgumentException("Cannot order with negative number of characters");
      }
      final int ref = r;
      return 
         new Comparator<Term>() {
            public int compare(Term t1, Term t2) {
               String q1 = t1.query;
               String q2 = t2.query;
               int min;
               if (q1.length() < q2.length()) {
                  min = q1.length();
               } 
               else {
                  min = q2.length();
               }
               if (min >= ref) {
                  return q1.substring(0, ref).compareTo(q2.substring(0, ref));
               } 
               else if (q1.substring(0, min).compareTo(q2.substring(0, min)) == 0) {
                  if (q1.length() == min) {
                     return -1;
                  } 
                  else {
                     return 1;
                  }
               } 
               else {
                  return q1.substring(0, min).compareTo(q2.substring(0, min));
               }
            }
         };
   }

   public int compareTo(Term that) {
      String q1 = this.query;
      String q2 = that.query;
      return q1.compareTo(q2);
   }

   public long getWeight() {
      return this.weight;
   }

   public String toString() {
      return this.weight + "\t" + this.query;
   }
}

BinarySearchDeluxe

 import java.lang.*;
import java.util.*;
import java.util.Comparator;
public class BinarySearchDeluxe {

    public static <Key> int firstIndexOf(Key[] a, Key key, Comparator<Key> comparator) {
        if (a == null || key == null || comparator == null) {
            throw new java.lang.NullPointerException();
        }
        if (a.length == 0) {
            return -1;
        }
        int left = 0;
        int right = a.length - 1;
        while (left + 1 < right) {
            int middle = left + (right - left)/2;
            if (comparator.compare(key, a[middle]) <= 0) {
                right = middle;
            } else {
                left = middle;
            }
        }
        if (comparator.compare(key, a[left]) == 0) {
            return left;
        }
        if (comparator.compare(key, a[right]) == 0) {
            return right;
        }
        return -1;

    }

    public static <Key> int lastIndexOf(Key[] a, Key key, Comparator<Key> comparator) {
        if (a == null || key == null || comparator == null) {
            throw new java.lang.NullPointerException();
        }
        if (a == null || a.length == 0) {
            return -1;
        }
        int left = 0;
        int right = a.length - 1;
        while (left + 1 < right) {
            int middle = left + (right - left)/2;
            if (comparator.compare(key, a[middle]) < 0) {
                right = middle;
            } else {
                left = middle;
            }
        }
        if (comparator.compare(key, a[right]) == 0) {
            return right;
        }
        if (comparator.compare(key, a[left]) == 0) {
            return left;
        }
        return -1;
    }
}

AutoComplete

import java.util.Arrays;
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
import java.util.Comparator;

public class Autocomplete {
   public Term[] terms;

   public Autocomplete(Term[] terms) {
      if (terms == null) {
         throw new java.lang.NullPointerException();
      }
      this.terms = terms.clone();
      Arrays.sort(this.terms);
   }

   public Term[] allMatches(String prefix) {
      if (prefix == null) {
         throw new java.lang.NullPointerException();
      }
      Term theTerm = new Term(prefix, 0);
      int start = BinarySearchDeluxe.firstIndexOf(terms, theTerm, Term.byPrefixOrder(prefix.length()));
      int end = BinarySearchDeluxe.lastIndexOf(terms, theTerm, Term.byPrefixOrder(prefix.length()));
      int count = start;
      System.out.println("Start: " + start + " End: " + end);
      if (start == -1 || end == -1) {
         // System.out.println("PREFIX: " + prefix);
         throw new java.lang.NullPointerException();
      } // Needed?
      Term[] matches = new Term[end - start + 1];
      //matches = Arrays.copyOfRange(terms, start, end);
      for (int i = 0; i < end - start; i++) {
         matches[i] = this.terms[count];
         count++;
      }
      Arrays.sort(matches, Term.byReverseWeightOrder());
      System.out.println("Finished allmatches");
      return matches; 
   }

   public int numberOfMatches(String prefix) {
      if (prefix == null) {
         throw new java.lang.NullPointerException();
      }
      Term theTerm = new Term(prefix, 0);
      int start = BinarySearchDeluxe.firstIndexOf(terms, theTerm, Term.byPrefixOrder(prefix.length()));
      int end = BinarySearchDeluxe.lastIndexOf(terms, theTerm, Term.byPrefixOrder(prefix.length()));
      System.out.println("Finished numberMatches");
      return end - start + 1; // +1 needed?
   }

    public static void main(String[] args) throws IOException {
      // Read the terms from the file
      Scanner in = new Scanner(new File("wiktionary.txt"));
      int N = in.nextInt(); // Number of terms in file
      Term[] terms = new Term[N];
      for (int i = 0; i < N; i++) {
         long weight = in.nextLong(); // read the next weight
         String query = in.nextLine(); // read the next query
         terms[i] = new Term(query.replaceFirst("\t",""), weight); // construct the term
      }
      Scanner ip = new Scanner(System.in);  
   // TO DO: Data Validation Here
      int k;
      do {
         System.out.println("Enter how many matching terms do you want to see:");
         k = ip.nextInt();
      } while (k < 1 || k > N);
      Autocomplete autocomplete = new Autocomplete(terms);
   // TO DO: Keep asking the user to enter the prefix and show results till user quits
      boolean cont = true;
      do {
         // Read in queries from standard input and print out the top k matching terms
         System.out.println("Enter the term you are searching for. Enter * to exit");
         String prefix = ip.next();
         if (prefix.equals("*")) {
            cont = false;
            break;
         }
         Term[] results = autocomplete.allMatches(prefix);
         System.out.println(results.length);
         for(int i = 0; i < Math.min(k,results.length); i++)
            System.out.println(results[i].toString());
      } while(cont);

      System.out.println("Done!");
   }
}

I apologize for the sloppy code, I have been pulling my hair out for awhile now and keep forgetting to clean it up.

Two examples:

Example 1:

int k = 2;
String prefix = "auto";

Enter how many matching terms do you want to see:

2

Enter the term you are searching for. Enter * to exit

auto

619695 automobile

424997 automatic

Example 2:

int k = 5;
String prefix = "the";

Enter how many matching terms do you want to see:

5

Enter the term you are searching for. Enter * to exit

the

5627187200 the

334039800 they

282026500 their

250991700 them

196120000 there

0

There are 0 answers