user3376836
user3376836

Reputation: 21

How to find the minimum value from a generic arraylist?

I am having trouble trying to write a method to return the object that has the least volume in a generic ArrayList. These are the guidelines I was given to write the code:

min() - This method takes an ArrayList of Bounded Generic Type which only allows Shape objects and its subclasses. - The method should return the object with the minimum volume from the list of objects.

But I'm not entirely sure if I even followed it right. Is there a way I could use the Collections.min (and Collections.max since I have to write a max volume method too)? I get a bound mismatch error saying: The generic method min(Collection) of type Collections is not applicable for the arguments (ArrayList). The inferred type Shape is not a valid substitute for the bounded parameter >

My Shape class is simply an interface with a getVolume(); method where my other classes (Spheres, Ellipsoids, etc.) override this method:

public interface Shape {
    public double getVolume();
}

And here is my min method (in another class with other methods) I'm having problems with:

public static <T> T  min() {
    ArrayList<? extends Shape> list;    

     T min = Collections.min(list));
        return min;

Upvotes: 1

Views: 6791

Answers (5)

navinmurrari
navinmurrari

Reputation: 1

public <E extends Comparable> E getMin(List<E> list){
    E min = null;
    for(E element:list){
        if(min == null){
            min = element;
            continue;
        }
        if(element.compareTo(min) < 0){
            min = element;
        }
    }
    return min;
}

Upvotes: 0

Michael Anderson
Michael Anderson

Reputation: 73470

There are two options in java.utils.Collections.

  • static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
  • static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp)

The first of these requires your Shape to implement Comparator<Shape>

class Shape implements Comparable<Shape> {
    int compareTo(Shape other) {
       return Math.signum(getVolume()-other.getVolume);
    }
    ...
}

ArrayList<Shape> myShapes = ...
Shape minShape = Collections.min(myShapes);

The second requires you to create a custom comparator:

class Shape {
    ...
}

class ShapeVolumeComparator implements Comparator<Shape> {
    int compare(Shape s1, Shapes2) {
       return Math.signum(s1.getVolume()-s2.getVolume());
    }
}

ArrayList<Shape> myShapes = ...;
Shape minShape = Collections.min(myShapes, new ShapeVolumeComparator() );

The first is less code, but the second is more adaptable if you want to sort on something else - say surface area, or position.

Upvotes: 1

Luc DUZAN
Luc DUZAN

Reputation: 1319

You should this method http://www.tutorialspoint.com/java/util/collections_min_comparator.htm and provide a comparator :

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;

public abstract class Shape {
    public abstract double getVolume();

    public Shape min(Collection<? extends Shape> col) {
        return Collections.min(col, new Comparator<Shape> () {
            public int compare(Shape l, Shape r) {
                return ((Double) l.getVolume()).compareTo(r.getVolume());
            }
        });
    }
}

Upvotes: -1

PurkkaKoodari
PurkkaKoodari

Reputation: 6809

To compare the volumes, you can make Shape Comparable or use a Comparator.

Comparable

This requires changes to all shapes, but none to the code using them. I used an abstract class to easily put the comparing to all classes.

public interface Shape extends Comparable<Shape> {
    public double getVolume();
}

public abstract class BaseShape implements Shape {
    public int compareTo(Shape other) {
        return Double.compare(getVolume(), other.getVolume());
    }
} 

public class Box extends BaseShape {
    public double getVolume() {
        return volume;
    } 
} 
public class Ball extends BaseShape { /* ... */ } 

And to use:

Collections.min(collection);

Comparator

This needs no modification to the shapes, but a bit more code to use them.

public class ShapeComparator implements Comparator<Shape> {
    public int compare(Shape a, Shape b) {
        return Double.compare(a.getVolume(), b.getVolume());
    } 
} 

And to use:

Collections.min(collection, new ShapeComparator());

Upvotes: 1

Justin Mitchell
Justin Mitchell

Reputation: 304

It's because Java erases type at runtime, so the Collection doesn't know what type it's actually dealing with. It's a limiting factor when using Java generics - I've bumped heads with it before a few years ago but I couldn't figure out a way to get around it and it turned out to be a language restriction.

The best thing to do is create a public T getMinVolume(ArrayList<T> list) method to iterate through each T.

eg.

public T getMinVolume(ArrayList<T> list) {
    T min = null;
    for(T item: list) {
        if (min == null) {
            min = item;
        }

        if (min > item) {
            min = item;
        }
    }

    return min;
}

Something like that, my Java is a bit rusty but the logic should work.

Upvotes: 1

Related Questions