2

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?

9
  • 4
    Create a comparable class FooBar. It holds a reference to a Foo and another to a Bar. It is comparable with other FooBar instances based on your criteria. Commented Feb 28, 2018 at 17:10
  • And what about sorting both lists from 0 to limit? Would it work for you? Commented Feb 28, 2018 at 17:12
  • 2
    Should not you do positions.get( obj1.getId() )? Commented Feb 28, 2018 at 17:17
  • Can you explain the intended behaviour when Foo (value) and Bar (id) values are disjoint? Commented Feb 28, 2018 at 17:25
  • In other words - Can Bar have an id that is not there in Foo? Commented Feb 28, 2018 at 17:27

2 Answers 2

1

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 = {a1, a2...an} and B = {b1, b2, ...bm}, 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).

Sign up to request clarification or add additional context in comments.

2 Comments

Could you explain why this is the solution?
@EmilSundvall Have you made sure Foo does not have any value that is not there in Bar (Bar.id). Also, make sure there are no nulls in the Bar list.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.