user3772547 user3772547 - 7 months ago 8
Java Question

how do you sort a collection of a custom object by a field which is itself an object java

I'm using Processing.

public void sortEnemies(final String field, List<Enemy> itemLocationList) {
Collections.sort(itemLocationList, new Comparator<Enemy>() {
@Override
public int compare(Enemy o1, Enemy o2) {
if (field.equals("r")) {
if (o1.r<o2.r)
{
return -1;
}
if (o1.r>o2.r)
{
return 1;
}
if (o1.r==o2.r)
{
return 0;
}
}

println("shoudl not have reached here.");
return 0;
}
}
);
}


It's easy enough to use a comparator to sort these enemies i have by a primitive field such as their radius r. What I want to do is this: Each enemy has a PVector object called loc inside of it which has primitive fields loc.x and loc.y. How would I modify this code to sort by the PVector object within the object? Is that possible? I'd just like to sort, for example, by their x or y coordinate, but I'm not sure how to write it in a similar fashion.

Essentially the question is: how to sort an array of objects by a field which is itself an object that has the field I want to sort by.

edit: i see that there is a similar problem here
Sort ArrayList of custom Objects by property

but i don't want to use lambda notation since I don't think processing uses java 8 (not sure). I can't modify the PVector class. I have made a way to sort a list of PVector objects, but it seems like it would be a very roundabout way of making a list of the pvectors of enemies, getting the indices and then sorting the enemies with those indices.

Answer

From the comment feed:

I want to pass a String called field where i can say sortEnemies('x', listofenemies); and also sortEnemies('r', listofenemies);

I would suggest making a mapping of field names to comparators, like so:

Map<String, Comparator<Enemy>) comparators = new HashMap<>();

comparators.put("health", new Comparator<Enemy>() {
    @Override
    public int compare(Enemy o1, Enemy o2) {
        if (o1.health < o2.health)
            return -1;
        if (o1.health > o2.health)
            return 1;
        return 0;
    }
});

comparators.put("x", new Comparator<Enemy>(){
    @Override
    public int compare(Enemy o1, Enemy o2) {
        if (o1.loc.x < o2.loc.x)
            return -1;
        if (o1.loc.x > o2.loc.x)
            return 1;
        return 0;
    })
);

When you want to sort your items, get the appropriate comparator by name:

Comparator<Enemy> comparator = comparators.get("x");
if (comparator == null)
    throw new RuntimeException("No such comparator exists!");
Collections.sort(itemLocationList, comparator);

I would suggest fully qualifying the name, i.e. using "loc.x" as the name, rather than just "x", although it can be anything you like, as long as you use the same name when you put it in and get it out.

Comments