I think the easiest solution, just using the standard library, would probably be:
<T extends Comparable<? super T>> int[] getSortedIndices(List<? extends T> list) {
return getSortedIndices(list, Comparator.naturalOrder());
}
<T> int[] getSortedIndices(List<? extends T> list, Comparator<? super T> comparator) {
return IntStream.range(0, list.size())
.boxed()
.sorted(Comparator.comparing(list::get, comparator))
.mapToInt(i -> i)
.toArray();
}
That unfortunately boxes then unboxes each index. Also the Stream.sorted operation is stateful, so there might be memory concerns for large lists. If you profile either of those things to be a problem then you can try to implement a solution that sorts an int[] based on the elements of the list. Something like:
<T extends Comparable<? super T>> int[] getSortedIndices(List<? extends T> list) {
return getSortedIndices(list, Comparator.naturalOrder());
}
<T> int[] getSortedIndices(List<? extends T> list, Comparator<? super T> comparator) {
int[] indices = new int[list.size()];
// Initialize values: indices[i] = i
Arrays.setAll(indices, IntUnaryOperator.identity());
// Sort 'indices' based on elements of 'list'
boolean swapped;
do {
swapped = false;
for (int i = 1; i < indices.length; i++) {
int j = indices[i - 1];
int k = indices[i];
if (comparator.compare(list.get(j), list.get(k)) > 0) {
indices[i - 1] = k;
indices[i] = j;
swapped = true;
}
}
} while (swapped);
return indices;
}
Note that example uses Bubble Sort which is O(n^2); you will probably want to use a different sorting algorithm. There's likely a library out there that provides a way to sort an int[] with a custom Comparator so you don't have to implement it yourself. Though if you implement it yourself you might be able to find a way to avoid the cost of initializing the indices array (Arrays::setAll in the example).
Finally, be aware that both examples above expect the List to be random-access in order to perform well. An example of a random-access list implementation is ArrayList. Such implementations should implement the RandomAccess interface. If the list is not random-access (whether it implements RandomAccess or not) then the calls to get will no longer be O(1).