Reputation: 21
Suppose I have three arrays like such:
a = [1, 2, 1, 4, 1]
b = [6, 1, 2, 4, 3]
c = [9, 6, 4, 7, 8]
I'd like to sort them as if they were a tuple (a, b, c) so the result should look like:
a | b | c
----------------------
1 2 4
1 3 8
1 6 9
2 1 6
4 4 7
I'd like to write Java code that does this in the most efficient way possible. Thanks!
Upvotes: 2
Views: 145
Reputation: 19575
You should create a wrapper object implementing Comparable
interface, map the values in the arrays to the instances of this wrapper class, sort, and use the values.
Example:
static class X implements Comparable<X> {
final int a;
final int b;
final int c;
public X(int a, int b, int c) {
this.a = a;
this.b = b;
this.c = c;
}
public int getA() {return a;}
public int getB() {return b;}
public int getC() {return c;}
@Override
public int compareTo(X that) {
int cmp = Integer.compare(this.a, that.a);
if (cmp == 0) {
cmp = Integer.compare(this.b, that.b);
if (cmp == 0) {
cmp = Integer.compare(this.c, that.c);
}
}
return cmp;
}
}
public static void main(String[] args){
int[] a = {1, 2, 1, 4, 1};
int[] b = {6, 1, 2, 4, 3};
int[] c = {9, 6, 4, 7, 8};
IntStream.range(0, a.length)
.mapToObj(i -> new X(a[i], b[i], c[i]))
.sorted()
.forEach(x -> {
System.out.printf("%d\t%d\t%d\t\n", x.getA(), x.getB(), x.getC());
});
}
This code prints expected output:
1 2 4
1 3 8
1 6 9
2 1 6
4 4 7
If needed, you can set the sorted values back to the initial arrays.
Update You may also use improved version of the solution offered by Gerold Boser though it has certain limitations on the range of the input integers and/or the count of the arrays:
static int m = 0;
public static void main(String[] args) {
// range of integer values for 3 arrays is -2^20 ... 2^20 -1
// or 0..2^21 -1
final int[] a = { Integer.MAX_VALUE>>11, 1, 1, -4, Integer.MIN_VALUE/(1<<11) };
final int[] b = { 6, 1, 1, 4, 3 };
final int[] c = { 9, -6, -24, 7, 8 };
IntSummaryStatistics stats =
Stream.of(Arrays.stream(a), Arrays.stream(b), Arrays.stream(c))
.flatMapToInt(s -> s)
.summaryStatistics();
long min = stats.getMin();
long max = stats.getMax() - min + 1;
IntStream.range( 0, a.length )
// use long to fit multiplication results into 63 bits
.mapToLong( i -> (a[i] - min) * max * max + (b[i]-min) * max + (c[i]-min) )
.sorted()
.forEach( n -> {
// re-calculate long back to ints
a[m] = (int) (n / (max * max) % max + min);
b[m] = (int) (n / max % max + min);
c[m] = (int) (n % max + min);
System.out.printf("% 9d\t% d\t% d\t\n", a[m], b[m], c[m]);
m++;
});
}
Output:
-1048576 3 8
-4 4 7
1 1 -24
1 1 -6
1048575 6 9
Note The mentioned limitations may be overcome by using BigDecimal
instead of long
to avoid overflow when performing multiplication
Upvotes: 2
Reputation: 14782
import static java.lang.System.out;
import java.util.Arrays;
import java.util.stream.IntStream;
public class SO62961100 {
static int i;
public static void main( final String[] args ) {
final int[] a = { 1, 2, 1, 4, 1 };
final int[] b = { 6, 1, 2, 4, 3 };
final int[] c = { 9, 6, 4, 7, 8 };
IntStream.range( 0, a.length )
.map( i -> a[i] * 100 + b[i] * 10 + c[i] )
.sorted()
.forEach( n -> {
a[i] = n / 100 % 10;
b[i] = n / 10 % 10;
c[i++] = n % 10;
} );
out.printf( "a=%s%nb=%s%nc=%s",
Arrays.toString( a ),
Arrays.toString( b ),
Arrays.toString( c ) );
}
}
a=[1, 1, 1, 2, 4]
b=[2, 3, 6, 1, 4]
c=[4, 8, 9, 6, 7]
Upvotes: 1