简体   繁体   中英

Sorting an arraylist based on objects value in another arraylist in Java

I have an issue with sorting an Array List. In a class i have two Array Lists of different objects, we can call the objects Foo and Bar.

public class Foo() {
   int value;
   //Some other fields, and setters and getters.
}

public class Bar() {
   int id;
   //Same here...
}

So the list fooList can be totally scrambeled. Say that i have 16 Foos, but Foo with value 5 can be on index 13 and so on.

What i'm trying to do is to order barList to match fooList after these values. If Foo with value 5 is on index 13, i want Bar with value 5 to be on index 13. My last attempt was this, but no success.

HashMap<Integer, Integer> positions = new HashMap<>();
for(int i=0;i<fooList.size();i++){
    positions.put(foo.get(i).getValue, i);
}
Collections.sort(barList, new Comparator<Bar>(){
    public int compare(Bar obj1, Bar obj2){
        return positions.get(barList.indexOf(obj1)) -
 positions.get(barList.indexOf(obj2));
    }
});

Does anybody have a clue how to do this in an efficient way?

I'm not sure why you are using the index of an element in barList to look into the map positions .

This should help you

Collections.sort(barList, new Comparator<Bar>() {
    @Override
    public int compare(Bar o1, Bar o2) {
        return positions.get(o1.getId()) - positions.get(o2.getId());
    }
});

This can be simplified with a one-liner

Collections.sort(barList, Comparator.comparingInt(bar -> positions.get(bar.getId())));

Basically, the problem boils down to this:

Given two lists of integers A = {a 1 , a 2 ...a n } and B = {b 1 , b 2 , ...b m }, sort the list B based on the position of occurrence of the element in the first list, A.

For two elements x , y in B

  • x > y , if x appears before y in A.
  • x < y , if x appears after y in A.
  • x = y , if x = y

So, the comparator function for Bar has to compare the position at which a particular element has appeared in Foo (based on the above).

NOTE: This assumes (as you have said) that there is no element in Bar that is not there in Foo . (The elements in Bar are a subset of the elements in Foo ).

I'd first index items of the barList on values so that it would be possible to quickly find a Bar instance with the appropriate value. Then use it to transform the fooList into the new barList . Something along the lines:

Map<Integer, Bar> barMap = barList
    .stream()
    .collect(Collectors
        .toMap(
            Bar::getValue,
            Function.identity());
barList = fooList
    .stream()
    .map(Foo::getValue)
    .map(barMap::get)
    .collect(Collectors.toList());

I think this must be as optimal as it gets in terms of time. In the expence of memory, you have to build a barMap here.

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