1

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.

Community
  • 1
  • 1
user3772547
  • 165
  • 10

1 Answers1

1

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.

This answer is rather different to the original answer, but you can see the different versions by clicking on the 'edited' link below.

Andrew Williamson
  • 8,299
  • 3
  • 34
  • 62
  • I am accepting the answer because It worked. (Just need to fix the o1.r to o1.x in your example as well as maybe rename Enemey to Enemy). Just for clarification, to be able to sort by other fields, do I just have to add new compare methods or do i just add a field called String, and then do like i did above in my example? – user3772547 Apr 23 '16 at 05:14
  • I'm not sure I fully understand that last bit... I'll update the answer, but comment again if it's still not clear. – Andrew Williamson Apr 23 '16 at 05:20
  • Sorry let me say it in a different way. I want to pass a String called field where i can say sortEnemies('x', listofenemies); and also sortEnemies('r', listofenemies); x is the member of the pvector, which we did. but r is a member of the enemy itself. Do i have to implement another compare method because the method signature is different? – user3772547 Apr 23 '16 at 05:27
  • cool, this is an interesting way to go. it seems you get what im tryingto do with getting enemy characteristics :) i haven't used hashmaps before, so I don't quite get whats going on, but I'll give it a shot and see what happens. since this answer is a bit different than your previous one, do you want to include your original answer too for completeness? i think generally it might be helpful to others to see both solutions – user3772547 Apr 23 '16 at 05:51
  • I added a note at the bottom of the answer, but I don't think it's worth including the previous answer because it didn't really solve the question. HashMaps are fairly straight-forward to use - you put in a key and a value, and you use the key to get back the value. In this case, the key is the name of the field you want to sort by, and the value is a comparator which sorts enemies by that field. – Andrew Williamson Apr 23 '16 at 05:56
  • change ')' to '>' in first line? can't seem to do it myself. actualy i dunno what to fix – user3772547 Apr 23 '16 at 06:04
  • got it to work. i had to remove the <> in the first line after new HashMap. – user3772547 Apr 23 '16 at 06:23
  • What? Really? Doesn't that give you a big warning, saying "Unparameterized usage of the generic type HashMap", or something along those lines? Instead of taking it completely out, you could also fill it in, because older versions of Java are not good with the implicit typing: `new HashMap>();` – Andrew Williamson Apr 23 '16 at 06:26
  • it didn't give any warning. I can't actually put what you wrote there. it ssays.incorrect number of arguments for type HashMap ; it vannot be parameters with aguments > – user3772547 Apr 23 '16 at 06:29
  • Yeah, I missed the Key type... So many typos in one day... `new HashMap>();` – Andrew Williamson Apr 23 '16 at 06:30
  • Hi again. I had a question, but didn't know how else to get in contact. So far solution has worked great. I have another situation where I'd like to sort them by their distance to an arbitrary location. So I'd say something like comparators.get("distanceTo"); but it would have to be something that I could pass, like a PVector object that has an x and y component. I tried to do it by creating a temp float field that i would call another function on before and then fill that temp float value and then sort like I usually do based on it. Is that a good solution or is there a better way? – user3772547 Jul 02 '16 at 16:41
  • The solution you're using is pretty much the only way to do it in Java 7 and lower. In Java 8, they introduced lambda expressions, which make programming with functions so much easier - if you have the option, I would recommend using it. – Andrew Williamson Jul 02 '16 at 22:51