Method 1 (extract indexes first and construct new list)
If you can change the data format and use a custom object, I recommend to use method 2.
You can first extract the indexes of the original elements in at
into an array sortedIndices
. If the list is already sorted, the value would be [1, 2, 3, ..., n-1]
. If the first two elements need to be swapped, the value would be [1, 0, 2, 3, ..., n-1]
. Afterwards, you can construct and populate the two sorted lists (btSorted
/prcSorted
) by adding the elements according to the position stored sortedIndices[i]
.
ArrayList<Integer> at = new ArrayList<>(Arrays.asList(2, 0, 2, 3, 4));
ArrayList<Integer> bt = new ArrayList<>(Arrays.asList(2, 1, 3, 5, 4));
ArrayList<String> prc = new ArrayList<>(Arrays.asList("p1", "p2", "p3", "p4", "p5"));
// get indexes of a sorted 'at' list
int[] sortedIndices = IntStream.range(0, at.size())
.boxed().sorted(Comparator.comparing(at::get))
.mapToInt(x -> x).toArray();
// sort 'bt' according to 'at'
ArrayList<Integer> btSorted = new ArrayList<>();
for (int i = 0; i < sortedIndices.length; i++) {
btSorted.add(bt.get(sortedIndices[i]));
}
// sort 'prc' according to 'at'
ArrayList<String> prcSorted = new ArrayList<>();
for (int i = 0; i < sortedIndices.length; i++) {
prcSorted.add(prc.get(sortedIndices[i]));
}
// sort 'at' directly (just for inspection)
ArrayList<Integer> atSorted = new ArrayList<>(at);
Collections.sort(atSorted);
System.out.println("idx: " + Arrays.toString(sortedIndices));
System.out.println("at: " + at + " => " + atSorted);
System.out.println("bt: " + bt + " => " + btSorted);
System.out.println("prc: " + prc + " => " + prcSorted);
Output:
idx: [1, 0, 2, 3, 4]
at: [2, 0, 2, 3, 4] => [0, 2, 2, 3, 4]
bt: [2, 1, 3, 5, 4] => [1, 2, 3, 5, 4]
prc: [p1, p2, p3, p4, p5] => [p2, p1, p3, p4, p5]
Method 2 (custom class and Comparator
)
Much more readable would be to store the data in a custom class (e.g. DataEntry
). Then, you can easily sort the array of objects (e.g. data
) without resorting to hard to read code:
ArrayList<DataEntry> data = new ArrayList<>();
data.add(new DataEntry(2, 2, "p1"));
data.add(new DataEntry(0, 1, "p2"));
data.add(new DataEntry(2, 3, "p3"));
data.add(new DataEntry(3, 5, "p4"));
data.add(new DataEntry(4, 4, "p5"));
// sort data by 'at'
data.sort(Comparator.comparing(d -> d.at));
// print result
data.forEach(d -> System.out.println(d.at + ", " + d.bt + ", " + d.prc));
Output:
0, 1, p2
2, 2, p1
2, 3, p3
3, 5, p4
4, 4, p5
DataEntry
class for reference:
static class DataEntry {
int at;
int bt;
String prc;
public DataEntry(int at, int bt, String prc) {
this.at = at;
this.bt = bt;
this.prc = prc;
}
}
Method 3 (with indexOf
and Comparator
)
This is only stable when there are no duplicates in the lists to be sorted (bt
/prc
) since indexOf
always returns the index of the first occurrence of the specified element in a list (or -1).
Sorting the lists could be done with a custom Comparator
and indexOf
. We can refer to the values in at
at the respective position of the current element being compared (d
) in the other lists (bt
/prc
) in order to sort them:
ArrayList<Integer> at = new ArrayList<>(Arrays.asList(2, 0, 2, 3, 4));
ArrayList<Integer> bt = new ArrayList<>(Arrays.asList(2, 1, 3, 5, 4));
ArrayList<String> prc = new ArrayList<>(Arrays.asList("p1", "p2", "p3", "p4", "p5"));
// sort 'bt' according to 'at'
ArrayList<Integer> btSorted = new ArrayList<>(bt);
btSorted.sort(Comparator.comparing(d -> at.get(bt.indexOf(d))));
// sort prc according to 'at'
ArrayList<String> prcSorted = new ArrayList<>(prc);
prcSorted.sort(Comparator.comparing(d -> at.get(prc.indexOf(d))));
// sort 'at' (just for inspection)
ArrayList<Integer> atSorted = new ArrayList<>(at);
Collections.sort(atSorted);
// print result
System.out.println(at + " => " + atSorted);
System.out.println(bt + " => " + btSorted);
System.out.println(prc + " => " + prcSorted);
Output:
at: [2, 0, 2, 3, 4] => [0, 2, 2, 3, 4]
bt: [2, 1, 3, 5, 4] => [1, 2, 3, 5, 4]
prc: [p1, p2, p3, p4, p5] => [p2, p1, p3, p4, p5]