Sorting multiple ArrayList synchronously

Viewed 68

I have multiple parallel ArrayList, I am sorting one of them (i.e. indexes).

ArrayList<Integer> indexes = {2,3,1};
ArrayList<String> names = {"two","three","one"}; 
ArrayList<String> upper = {"TWO","THREE","ONE"};

I want to synchronise the sorting of the ArrayList 'indexes' with the others ArrayList. I am wondering in the Collections.sort(list) would give me a clue?

2 Answers

It sounds like you want to sort one array by its values, and then rearrange two other arrays so that the arrangement of their values matches the sort order of the first array.

An easy way to do this is to sort an array of indexes into the ordering that you want, and then use this to rearrange the other arrays into the same order. Since one of your arrays is already called "indexes" I'll call this new array the "permutation".

First, create the permutation array by generating index values from zero to size-1 and then sorting them. They end up being sorted not according to their own values, but by the values in your index array:

List<Integer> indexes = List.of(2,3,1);
List<String> names = List.of("two","three","one");
List<String> upper = List.of("TWO","THREE","ONE");

List<Integer> permutation = IntStream.range(0, indexes.size())
                                     .boxed()
                                     .sorted(comparing(indexes::get))
                                     .collect(toCollection(ArrayList::new));

(So far, this is similar to the technique from Eritrean's answer.)

Now, we need to rearrange some data array according to the arrangement from the permutation array. Since we're doing this multiple times, here's a function that does that:

static <T> List<T> permute(List<Integer> permutation, List<T> list) {
    return IntStream.range(0, permutation.size())
                    .mapToObj(i -> list.get(permutation.get(i)))
                    .toList();
}

Now it's a simple matter to apply this to each of the data arrays:

System.out.println(permute(permutation, indexes));
System.out.println(permute(permutation, names));
System.out.println(permute(permutation, upper));

The result is

[1, 2, 3]
[one, two, three]
[ONE, TWO, THREE]

Note that this creates new lists in the desired arrangement. It's possible to permute the data arrays in-place, but it's somewhat more work, though not intractable. (Search for "[java] permute array in place" for ideas.)

Create a priority list from your indexes and use the index of the elemnts as a sorting criteria:

public static void main(String args[]) {
    List<Integer> indexes = new ArrayList<>(List.of(2,3,1));
    List<String> names    = new ArrayList<>(List.of("two","three","one"));
    List<String> upper    = new ArrayList<>(List.of("TWO","THREE","ONE"));

    List<Integer> priority = IntStream.range(0, indexes.size())
                                      .boxed()
                                      .sorted(Comparator.comparingInt(indexes::get))
                                      .collect(Collectors.toList());


    names.sort(Comparator.comparingInt(i -> priority.indexOf(names.indexOf(i))));
    upper.sort(Comparator.comparingInt(i -> priority.indexOf(upper.indexOf(i))));
    indexes.sort(Comparator.comparingInt(i -> priority.indexOf(indexes.indexOf(i))));

    System.out.println(indexes);
    System.out.println(names);
    System.out.println(upper);
}
Related