简体   繁体   中英

How to sort ArrayList according to another ArrayList?

I've got two ArrayList<JLabel> :

ArrayList<JLabel> label1 = new ArrayList<JLabel>();
ArrayList<JLabel> label2 = new ArrayList<JLabel>();

label1 contains names (like "John" or "car") and label2 contain ratings (like "8.5" or "10.0"). I wanna sort both lists by rating.

I've used Collections.sort(label2, new Sort()); to sort label2 , but I have no idea how to sort label1 in exaclty the same way (using label2 objects). Here is my Comparator class:

class Sort implements Comparator<JLabel>{
    public int compare(JLabel o1, JLabel o2) {
        Double a = Double.parseDouble(o1.getText());
        Double b = Double.parseDouble(o2.getText());
        return  b.compareTo(a);
    }
}

Any ideas?

Given that you have no relationship defined between the two lists I think you should consider wrapping the two values up in a class:

class Foo {

   private String name;
   private double rating;

   public Foo(String name, double rating){
       this.name = name;
       this.rating = rating;
   }

   // getters & setters
}

You can then have List<Foo> and sort the list based on the value of rating.

In Java 8 this would be as simple as calling the sort() method, which is now provided in List , with a lambda expression passed in.

Let's solve this using a Map . We'll first define a comparator to sort descending by value, like so:

class NumericComparator extends Comparator {
    Map map;
    public NumericComparator(Map map) {
        this.map = map;
    }

    public int compare(Object o1, Object o2) {
        return ((Integer) map.get(o2)).compareTo((Integer) map.get(o1));
    }
}

We'll define the name as the key, and the rating as the value. Like so:

Map<String, Double> carMap = new HashMap<>();
//we can populate the map like so:
carMap.put("John", 10d); //works nicely in loops

Then we take that unsorted map, and insert all of it's values into a TreeMap , that implements the NumericComparator we defined earlier.

NumericComparator nc = new NumericComparator(carMap);
Map<String, Double> sortedMap = new TreeMap(nc);
sortedMap.putAll(carMap);

First, please program to the List interface. Next, I'm assuming you can use apache libraries, there is Pair<L, R> in apache commons-lang (or you could implement your own tuple class; or use another like this one ). Regardless, you'll need to modify your Comparator to operate on the right-hand side (and I personally like to use the left-hand side to break ties). Finally, if you want to use label1 and label2 you'll need to copy the values back (after sorting). Something like,

List<JLabel> label1 = new ArrayList<>();
List<JLabel> label2 = new ArrayList<>();
// ...
List<Pair<JLabel, JLabel>> pairs = new ArrayList<>();
int len = label1.size();
if (len == label2.size()) {
    for (int i = 0; i < len; i++) {
        pairs.add(Pair.of(label1.get(i), label2.get(i)));
    }
    Collections.sort(pairs, new Comparator<Pair<JLabel, JLabel>>() {
        @Override
        public int compare(Pair<JLabel, JLabel> o1,
                Pair<JLabel, JLabel> o2) {
            double a = Double.parseDouble(o1.getRight().getText());
            double b = Double.parseDouble(o2.getRight().getText());
            int ret = Double.compare(a, b);
            if (ret != 0) {
                return ret;
            } // if ret is 0, it's a tie.
            return o1.getLeft().getText()
                    .compareTo(o2.getLeft().getText());
        }
    });
    // ... only if you need to use label1 and label2 after the sort.
    for (int i = 0; i < len; i++) {
        label1.set(i, pairs.get(i).getLeft());
        label2.set(i, pairs.get(i).getRight());
    }
}

Good question -- and also a hassle for me when sorting player order by dice-throw in a board game app.

The previous answer of binding the two lists within a new gross object or in a map (when all the strings are unique) is fine.

But if you do want something simpler then here is this.
I was originally doing this without referencing a deep copy of the original comparison list and it was getting some of the sorting right and some odd entries mixed in . . . Eventually I saw the light and made a deep copy (label11) of the original list. Also ensure to put the sorting code into a private method so as to enable access to the two lists, label11 & label2, by the sort Comparator's overriding compare(..) method.

 . . . .
 . . . .

ArrayList<JLabel> label1 = new ArrayList<JLabel>(); // String list
ArrayList<JLabel> label2 = new ArrayList<JLabel>(); // Double list 
System.out.println("Original String list : " + label1); // Check original list
sortByValue(label1, label2);  // Sort label1 by label2 order descending
System.out.println("Sorted String list: " + label1);    // Check sorted list

. . . . 
. . . . 

/** Private static method to facilitate access to list being sorted and 
  * the list used as a sort criterion by the code in the sort Comparator's 
  * overriding compare(..) method. */
private static void sortByValue(ArrayList<JLabel> label1,
                                ArrayList<JLabel> label2)
{
   ArrayList<JLabel> label11 = 
     new ArrayList<JLabel>(label1);     // Deep copy original string list
   Collections.sort(list1, new Comparator<JLabel>()
   {
     @Override
     public int compare(JLabel x, JLabel y)
     {
      return                            // Sort by descending label2 values
       (Double.parseDouble(label2.get(label11.indexOf(y)).getText())
        -Double.parseDouble(label2.get(label11.indexOf(x)).getText()))
        .intValue();
     }
   });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM