1

I'm struggling to make a comparator for binary search work on an array of objects. Essentially the goal is to search a ragged array to find the first match of an item OR the closest match to provide an insert point. The method passes in an generic (this is unchangeable - as this is homework) but you can't create arrays of generic types... so, my comparator is throwing an error: "The method binarySearch(Object[], Object) in type Arrays is not applicable for the arguments (Object[], E, Comparator)". Perhaps I need to cast the generic element "item"? I'm not sure. Code:

private Location findFirst(E item) {
    Location current;
    int closestMatchArray1;
    int closestMatchArray2;

Object[] firstItemInArray2 = new Object[numArrayInUse];
Object firstItem;

Comparator<E> comparator = new CompareElement();

for (int i - 0; i < numArrayInUse; i++) {
    firstItem = topArray[i];
    firstItemInArray2[i] = firstItem;
}

closestMatchArray1 = Arrays.binarySearch(firstItemInArray2, item, comparator);

Secondary, but related question. In the comparator, I am attempting to invoke the Comparable method "compareTo" to obtain a negative integer that gives an approximate location for where an item would be if it were in the array on a failed search, but again, I'm having trouble with generics, getting this error: "The method compareTo(E) is undefined for the type E". Code:

public class CompareElement implements Comparator<E> {
  public int compare(E firstItem, E secondItem) {
     return firstItem.compareTo(secondItem);
  }
}
7
  • Can you tell us exactly what error messages you get, and when/where? Commented Oct 11, 2012 at 12:52
  • Can't use List, although it would be nice. Error messages are: "The method binarySearch (Object[], Object) in the type Arrays is not applicable for the arguments (Object[], E, Comparator<E>). And "The method compareTo(E) is undefined for the type E". Commented Oct 11, 2012 at 12:56
  • @KingTriumph - Update your post with that error. Commented Oct 11, 2012 at 12:57
  • 1
    Do yo have a class named E? Commented Oct 11, 2012 at 12:59
  • 2
    "The method compareTo(E) is undefined for the type E". compareTo is a method from Comparable. In your CompareElement class, E must be declared, i.e. public class CompareElement<E extends Comparable> implements Comparator<E> Commented Oct 11, 2012 at 13:07

4 Answers 4

1

I think you either need a Comparator<Object> or you need an array of E[]. For the latter, I would suggest checking out these two articles:

Above reading is encouraged.


Option 1: Array.newInstance()

assumes item is never null

Based on what I've read in the aforementioned posts, if you know item will never be null, you could try something like this ...

@SuppressWarnings("unchecked")
private Location findFirst(E item) {
    Location current;
    int closestMatchArray1;
    int closestMatchArray2;

    // Object[] firstItemInArray2 = new Object[numArrayInUse];
    // Object firstItem;

    E[] firstItemInArray2 
            = (E[]) Array.newInstance(item.getClass(), numArrayInUse); 
    E firstItem;

    Comparator<E> comparator = new CompareElement();

    for (int i = 0; i < numArrayInUse; i++) {
        firstItem = (E) topArray[i];
        firstItemInArray2[i] = firstItem;
    }

    closestMatchArray1 = Arrays.binarySearch(firstItemInArray2, item, comparator);

Option 2: Array.newInstance()

requires Class parameter

If you can't guarantee the item will never be null, and you can't provide any special handling for null values, you could force the Class<?> parameter to be passed in, as follows...

@SuppressWarnings("unchecked")
private Location findFirst(E item, Class<E> clazz) {
    Location current;
    int closestMatchArray1;
    int closestMatchArray2;

    // Object[] firstItemInArray2 = new Object[numArrayInUse];
    // Object firstItem;

    E[] firstItemInArray2 
            = (E[]) Array.newInstance(clazz, numArrayInUse); 
    E firstItem;

    Comparator<E> comparator = new CompareElement();

    for (int i = 0; i < numArrayInUse; i++) {
        firstItem = (E) topArray[i];
        firstItemInArray2[i] = firstItem;
    }

    closestMatchArray1 = Arrays.binarySearch(firstItemInArray2, item, comparator);

Option 3: Object Comparator Wrapper

ugly, but it works

Alternatively you can create a Comparator<Object> to wrap your existing Comparator<E>, as follows (I think it's a bit of a hack, but it works consistently for me) ...

    private Location findFirst(E item) {
    Location current;
    int closestMatchArray1;
    int closestMatchArray2;

    Object[] firstItemInArray2 = new Object[numArrayInUse];
    Object firstItem;

    // Comparator<E> comparator = new CompareElement();
    Comparator<Object> comparator = new Comparator<Object>() {
        private final Comparator<E> delegate = new CompareElement();

        @Override
        @SuppressWarnings("unchecked")
        public int compare(Object o1, Object o2) {
            return delegate.compare((E) o1, (E) o2);
        }
    };

    for (int i = 0; i < numArrayInUse; i++) {
        firstItem = topArray[i];
        firstItemInArray2[i] = firstItem;
    }

    closestMatchArray1 = Arrays.binarySearch(firstItemInArray2, item, comparator);

Hope this helps!

Sign up to request clarification or add additional context in comments.

Comments

0

You have to pass Class<E> so you may instantiate an array of E. (As <E> is dropped at runtime, E is just Object.)

Class<E> klazz;

E[] firstItemInArray2 = (E[])
        java.lang.reflect.Arrays.newInstance(klazz, numArraysInUse);

Comments

0

You did not declare <E>. You would have to define your CompareElement as follows:

public class CompareElement<E extends Comparable> implements Comparator<E> {
    public int compare(E firstItem, E secondItem) {
        return firstItem.compareTo(secondItem);
    }
}

Then declare it as follows:

Comparator<?> comparator = new CompareElement<?>();

Whereas ? should be the type you want to compare.

Comments

0

Where is your E declared? It seems like some type parameter that is declared in some enclosing class that we can't see. It seems that your CompareElement class is a comparator that compares elements based on their natural ordering (i.e. according to Comparable). If so, then E must have a bound that guarantees that it is able to compare to itself, <E extends Comparable<? super E>>. You can change that bound where E is declared, or, if you want to do it like other people have suggested, to have CompareElement be parameterized separately from the enclosing class, you would do this:

public class CompareElement<E extends Comparable<? super E>> implements Comparator<E> {
  public int compare(E firstItem, E secondItem) {
     return firstItem.compareTo(secondItem);
  }
}

Your first error is because the version of binarySearch you're trying to use, the one with a comparator, has restrictions on the types of the arguments. It is declared like this: static <T> int binarySearch(T[] a, T key, Comparator<? super T> c). So If you have a Comparator<E>, then you will need an E[] as first parameter, whereas you have an Object[]. You have to think of some way to make it E[].

But actually for you you're trying to do you don't need to use a comparator at all. There is a version of the binarySearch method that does not take a comparator, and it already compares elements using their natural ordering.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.