2

While working on my project, I made a function to select a random object from an ArrayList. Each object has a variable min and max which defines the percentage the object has of being chosen.

The function works perfectly, but I use a dozen slight variations of it since I have a lot of ArrayLists with different types of objects, which I need to use it on. Therefore, I want to make it generic so I'd only have one variant of the function, which I can use for all my lists. At the moment, I have this:

public static <G> int selRan(ArrayList<G> list){
        int sel = 0;
        Random rand = new Random();
        int  randNum = rand.nextInt(100) + 1;
        for(int i = 0; i < list.size(); i++){
            if(list.get(i).min <= randNum && randNum < list.get(i).max){
                sel = i;
            }
        }
        return sel;
}

This is where I ran into a snag, as list.get(i).min and list.get(i).max don't work. I have no clue on how to approach this.

0xCursor
  • 2,242
  • 4
  • 15
  • 33
Ivaldir
  • 185
  • 12
  • I am not incredibly familiar with generics, but I believe you will still need to determine the type of the objects within the `ArrayList` at some point and process them differently. So a `switch` or `if`` tree is needed to check what type is being worked on. – Zephyr Jun 25 '18 at 18:24
  • 3
    You either check the type and case, or make it a list of things implementing a min/max interface. Personally I'd prefer the latter. – Dave Newton Jun 25 '18 at 18:25
  • 1
    Your generic type G should extend SomeSuperClassOrInterfaceWithMinAndMax. – JB Nizet Jun 25 '18 at 18:25
  • If not able/willing to implement an interface as others mentioned, you could do a simple `if (list.get(0) instanceof ClassType)` – Zephyr Jun 25 '18 at 18:26
  • @Zephyr (Which was also mentioned :) – Dave Newton Jun 25 '18 at 18:45
  • @DaveNewton - yes, by both of us :P – Zephyr Jun 25 '18 at 18:46

1 Answers1

7

Your type parameter G has no bound, so the compiler can't assume that any methods are available except for Object methods.

If you expect max and main to be available on different, unrelated objects that are in your lists, then create an interface that declares this functionality.

interface MinMax {
    int getMin();
    int getMax();
}

Have all your different, unrelated objects implements this interface. Then declare G with an upper bound of MinMax (or whatever you decide to call it), so that these methods will be guaranteed to be available to be called.

// Declare upper bound here.
public static <G extends MinMax> int selRan(ArrayList<G> list){
    int sel = 0;
    Random rand = new Random();
    int  randNum = rand.nextInt(100) + 1;
    for(int i = 0; i < list.size(); i++){
        // Call interface methods here.
        if(list.get(i).getMin() <= randNum && randNum < list.get(i).getMax()){
            sel = i;
        }
    }
    return sel;
}

You may also decide to program to the interface and accept a List<G> instead of an ArrayList<G> for flexibility.

You may find that you can just use a wildcard with the bound, because the exact type of G doesn't matter.

public static int selRan(List<? extends MinMax> list){
    int sel = 0;
    Random rand = new Random();
    int  randNum = rand.nextInt(100) + 1;
    for(int i = 0; i < list.size(); i++){
        // Call interface methods here.
        if(list.get(i).getMin() <= randNum && randNum < list.get(i).getMax()){
            sel = i;
        }
    }
    return sel;
}
rgettman
  • 176,041
  • 30
  • 275
  • 357