Java - Sort one array based on values of another array?
Solution 1:
In java 8, you can do this
with a lambda:
String[] strings = new String[]{"string1", "string2", "string3"};
final int[] ints = new int[]{40, 32, 34};
final List<String> stringListCopy = Arrays.asList(strings);
ArrayList<String> sortedList = new ArrayList(stringListCopy);
Collections.sort(sortedList, (left, right) -> ints[stringListCopy.indexOf(left)] - ints[stringListCopy.indexOf(right)]);
Or better, with Comparator:
String[] strings = new String[]{"string1", "string2", "string3"};
final int[] ints = new int[]{40, 32, 34};
final List<String> stringListCopy = Arrays.asList(strings);
ArrayList<String> sortedList = new ArrayList(stringListCopy);
Collections.sort(sortedList, Comparator.comparing(s -> ints[stringListCopy.indexOf(s)]));
Solution 2:
Short answer: I suggest that a separate class is created that holds the information about both the actual String
and the boosting (the int
). If you assume the following:
public class BoostString {
int boost;
String str;
public BoostString(int boost, String str) {
this.boost = boost;
this.str = str;
}
}
Then, you can sort your array by using a Comparator
and it works especially nice with the Java 8 Streaming API.
String[] strings = {"string1", "string2", "string3"};
int[] boosts = {40, 32, 34};
final String[] sorted = IntStream.range(0, boosts.length)
.mapToObj(i -> new BoostString(boosts[i], strings[i])) // Create the instance
.sorted(Comparator.comparingInt(b -> b.boost)) // Sort using a Comparator
.map(b -> b.str) // Map it back to a string
.toArray(String[]::new); // And return an array
The Comparator
in the example above is created using the Comparator.comparingInt
method which is a convenient way of creating a Comparator
for ints using Java 8.
Explanation: Typically when comparing objects in Java you use one of the built-in sorting functions such as Collections.sort
where you provide your own Comparator
. The Comparator
interface is straightforward and looks like this:
public interface Comparator<T> {
int compare(T o1, T o2);
// Other default methods for Java 8
}
The return value is of type int
and is described like this in the JavaDoc:
return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
This works out-of-the-box when you are sorting String
s or int
(or actually Integer
s) since they are Comparable
– they sort of have a built-in natural sorting and for String
s this is in alphabetical order and for Integers
this is sorted in ascending number order (see the JavaDoc for Comparable
).
On a side note, there are other "pair" or "tuple" implementations available if you are using 3rd party libraries. You do not have to create your own "pair" of a String
and int
. One example is the Pair class from Apache Commons.
Solution 3:
You can do something similar to your JS example in old style Java (but I would recommend joining your data together in an object as @wassgren suggests):
import java.util.*;
public class WeightSort {
public static void main(String[] args) {
String[] strings = new String[]{"string1", "string2", "string3"};
final int[] weights = new int[]{40, 32, 34};
final List<String> stringList = Arrays.asList(strings);
List<String> sortedCopy = new ArrayList<String>(stringList);
Collections.sort(sortedCopy, new Comparator<String>(){
public int compare(String left, String right) {
return weights[stringList.indexOf(left)] - weights[stringList.indexOf(right)];
}
});
System.out.println(sortedCopy);
}
}
Solution 4:
I solved this problem by using Comparator interface.
import java.util.Comparator;
import java.util.Collections;
import java.util.List;
import java.util.Arrays;
public class ComparatorDemo {
public static void main(String[] args) {
List<Area> metaData = Arrays.asList(
new Area("Joe", 24),
new Area("Pete", 18),
new Area("Chris", 21),
new Area("Rose",21)
);
Collections.sort(metaData, new ResultComparator());
for(int i =0 ;metaData.size()>i;i++)
System.out.println(metaData.get(i).output);
}
}
class ResultComparator implements Comparator<Area> {
@Override
public int compare(Area a, Area b) {
return a.result < b.result ? -1 : a.result == b.result ? 0 : 1;
}
}
class Area{
String output;
int result;
Area(String n, int a) {
output = n;
result = a;
}
}
Solution 5:
As @wassgren said, you can use streams, but you don't have to create a class, you can just use indexes:
String[] strings = {"string1", "string2", "string3"};
int[] boosts = {40, 32, 34};
String[] sorted = IntStream.range(0, boosts.length).boxed()
.sorted(Comparator.comparingInt(i -> boosts[i]))
.map(i -> strings[i])
.toArray(String[]::new);
First you create a stream of indexes, then you sort them acording to boosts and then you get the string in that index.