Sorting matched arrays in Java - java

Let's say that I have two arrays (in Java),
int[] numbers; and int[] colors;
Each ith element of numbers corresponds to its ith element in colors.
Ex, numbers = {4,2,1}
colors = {0x11, 0x24, 0x01}; Means that number 4 is color 0x11, number 2 is 0x24, etc.
I want to sort the numbers array, but then still have it so each element matches up with its pair in colors.
Ex. numbers = {1,2,4};
colors = {0x01,0x24,0x11};
What's the cleanest, simplest way to do this? The arrays have a few thousand items, so being in place would be best, but not required. Would it make sense to do an Arrays.sort() and a custom comparator? Using library functions as much as possible is preferable.
Note: I know the "best" solution is to make a class for the two elements and use a custom comparator. This question is meant to ask people for the quickest way to code this. Imagine being at a programming competition, you wouldn't want to be making all these extra classes, anonymous classes for the comparator, etc. Better yet, forget Java; how would you code it in C?

You could use sort() with a custom comparator if you kept a third array with the index, and sorted on that, leaving the data intact.
Java code example:
Integer[] idx = new Integer[numbers.length];
for( int i = 0 ; i < idx.length; i++ ) idx[i] = i;
Arrays.sort(idx, new Comparator<Integer>() {
public int compare(Integer i1, Integer i2) {
return Double.compare(numbers[i1], numbers[i2]);
}
});
// numbers[idx[i]] is the sorted number at index i
// colors[idx[i]] is the sorted color at index i
Note that you have to use Integer instead of int or you can't use a custom comparator.

It seems like the cleanest thing to do would be to create a custom property class that implements Comparable. For example:
class Color implements Comparable {
private int number;
private int color;
// (snip ctor, setters, etc.)
public int getNumber() {
return number;
}
public int getColor() {
return color;
}
public int compareTo(Color other) {
if (this.getNumber() == other.getNumber) {
return 0;
} else if (this.getNumber() > other.getNumber) {
return 1;
} else {
return -1;
}
}
}
Then you can separate your sorting algorithm from the ordering logic (you could use Collections.sort if you use a List instead of an array), and most importantly, you won't have to worry about somehow getting two arrays out of sync.

If you'd be willing to allocate some extra space, you could generate another array, call it extra, with elements like this:
extra = [0,1,...,numbers.length-1]
Then you could sort this extra array using Arrays.sort() with custom comparator (that, while comparing elements i and j really compares numbers[extra[i]] and numbers[extra[j]]). This way after sorting the extra array, extra[0] would contain the index of the smallest number and, as numbers and colours didn't move, the corresponding colour.
This isn't very nice, but it gets the job done, and I can't really think of an easier way to do it.
As a side note, in the competition I usually find the C++ templated pairs and nice maps indispensable ;)

Why not introduce an object to represent a number and a color and implement a comparator function for that?
Also, do you really need an array, why not use something derived from Collection?

I like #tovare's solution. Make a pointer array:
int ptr[] = { 1, 2, 3 };
and then when you sort on numbers, swap the values in ptr instead of in numbers. Then access through the ptr array, like
for (int i = 0; i < ptr.length; i++)
{
printf("%d %d\n", numbers[ptr[i]], colors[ptr[i]]);
}
Update: ok, it appears others have beaten me to this. No XP for me.

An example illustrating using a third index array. Not sure if this is the best implementation.
import java.util.*;
public class Sort {
private static void printTable(String caption, Integer[] numbers,
Integer[] colors, Integer[] sortOrder){
System.out.println(caption+
"\nNo Num Color"+
"\n----------------");
for(int i=0;i<sortOrder.length;i++){
System.out.printf("%x %d %d\n",
i,numbers[sortOrder[i]],colors[sortOrder[i]]);
}
}
public static void main(String[] args) {
final Integer[] numbers = {1,4,3,4,2,6};
final Integer[] colors = {0x50,0x34,0x00,0xfe,0xff,0xff};
Integer[] sortOrder = new Integer[numbers.length];
// Create index array.
for(int i=0; i<sortOrder.length; i++){
sortOrder[i] = i;
}
printTable("\nNot sorted",numbers, colors, sortOrder);
Arrays.sort(sortOrder,new Comparator<Integer>() {
public int compare(Integer a, Integer b){
return numbers[b]-numbers[a];
}});
printTable("\nSorted by numbers",numbers, colors, sortOrder);
Arrays.sort(sortOrder,new Comparator<Integer>() {
public int compare(Integer a, Integer b){
return colors[b]-colors[a];
}});
printTable("\nSorted by colors",numbers, colors, sortOrder);
}
}
The output should look like this:
Not sorted
No Num Color
----------------
0 1 80
1 4 52
2 3 0
3 4 254
4 2 255
5 6 255
Sorted by numbers
No Num Color
----------------
0 6 255
1 4 52
2 4 254
3 3 0
4 2 255
5 1 80
Sorted by colors
No Num Color
----------------
0 6 255
1 2 255
2 4 254
3 1 80
4 4 52
5 3 0

One quick hack would be to combine the two arrays with bit shifts. Make an array of longs such that the most significant 32 bits is the number and the least significant 32 is the color. Use a sorting method and then unpack.

Would it suffice to code your own sort method? A simple bubblesort would probably be quick to code (and get right). No need for extra classes or comparators.

Credit to #tovare for the original best answer.
My answer below removes the (now) unnecessary autoboxing via Maven dependency {net.mintern : primitive : 1.2.2} from this answer: https://stackoverflow.com/a/27095994/257299
int[] idx = new int[numbers.length];
for( int i = 0 ; i < idx.length; i++ ) idx[i] = i;
final boolean isStableSort = false;
Primitive.sort(idx,
(i1, i2) -> Double.compare(numbers[i1], numbers[i2]),
isStableSort);
// numbers[idx[i]] is the sorted number at index i
// colors[idx[i]] is the sorted color at index i

I guess you want performance optimization while trying to avoid using array of objects (which can cause a painful GC event).
Unfortunately there's no general solution, thought.
But, for your specific case, in which numbers are different from each others, there might be two arrays to be created only.
/**
* work only for array of different numbers
*/
private void sortPairArray(int[] numbers, int[] colors) {
int[] tmpNumbers = Arrays.copyOf(numbers, numbers.length);
int[] tmpColors = Arrays.copyOf(colors, colors.length);
Arrays.sort(numbers);
for (int i = 0; i < tmpNumbers.length; i++) {
int number = tmpNumbers[i];
int index = Arrays.binarySearch(numbers, number); // surely this will be found
colors[index] = tmpColors[i];
}
}
Two sorted arrays can be replace by Int2IntOpenHashMap, which performs faster run, but memory usage could be double.

You need to sort the colors array by its relative item in the numbers array. Specify a comparator that compares numbers and use that as the comparison for the colors array.

The simplest way to do this in C, would be bubblesort + dual pointers. Ofcourse the fastest would be quicksort + two pointers. Ofcourse the 2nd pointer maintains the correlation between the two arrays.
I would rather define values that are stored in two arrays as a struct, and use the struct in a single array. Then use quicksort on it. you can write a generic version of sort, by calling a compare function, which can then be written for each struct, but then you already know that :)

Use a TreeMap

Related

Finding common element in two arrays with best performing method

Implement a method that checks whether an integer is present in both integer array parameter 1 and integer array parameter 2 and prints the result of the search, with the best performance you can. The method parameters are: (1) the first integer array and (2) the second integer array of the same size as parameter 1 and (3) the integer to search for.
Note - Consider better performance to mean that a better performing method requires fewer general work steps to solve the problem with the same size of arrays. You may want to review the Java SE API page for java.util.Arrays
I was able to implement the solution but I am not sure if it the best-performing one because I am not using any java.util.Arrays methods as I am not sure which one to use necessarily to get me the best answer
public static void findCommonElements(int[] arr1, int[] arr2, int num){
for(int i = 0; i < arr1.length; i++){
for(int j = 0; j < arr2.length; j++){
if(arr1[i] == arr2[j] && arr1[i] == num){
System.out.println(num);
}
}
}
}
UPDATE:
I was able to update the code with following solution which completely removes for loop and implements binary for better performance
int[] arr1 = {7,8,5,1,2,3,6,7};
int[] arr2 = {9,8,6,4,1,2,4,5};
Arrays.sort(arr1);
Arrays.sort(arr2);
int index1 = Arrays.binarySearch(arr1, 5);
int index2 = Arrays.binarySearch(arr2, 5);
System.out.println(index1);
System.out.println(index2);
if(index1 < 0 || index2 < 0){
System.out.println("number not found in both arrays");
}
else{
System.out.println("number found in both arrays");
}
The problem description is a bit hard to follow, but by reference to the example code, I take this to be a fair rewording: "Write the best-performing method you can that takes two int arrays of the same length and a scalar int value i as parameters, and prints whether the value of i appears in both arrays."
Your first solution tests each pair of elements drawn one from the first array and the other from the second to determine whether they are equal to each other and to the target value. This is grossly inefficient for the problem as interpreted.
Your second solution sorts the arrays first, so as to be able to use a binary search to try to find the target element. This is better, but still inefficient. Although the binary searches are quite fast, the sorting required to prepare for them takes a lot more work than is saved by a single binary search.
Since it is sufficient to determine only whether the target value appears in both arrays, you can
scan each array for the target value, once, independently of the other.
skip the second scan if the first one does not find the target value
break early from each scan when the target value is found
The latter two are minor improvements, as they reduce only the minimum and average number of steps. The first, however, is a huge improvement, especially as array size increases, because for arrays of length n, then this requires a number of steps proportional to n in the worst case, whereas your first example code requires steps proportional to n2 in both the average and worst cases, and your second requires time proportional to n log n in the average and worst cases.
The implementation is left as the exercise it is intended to be. However, with respect to
I was able to implement the solution but I am not sure if it the
best-performing one because I am not using any java.util.Arrays
methods as I am not sure which one to use necessarily to get me the
best answer
, I don't think java.util.Arrays offers any method that particularly helps with this problem, especially given the orientation toward best possible performance.
You can use search the arrays using streams:
public static boolean findCommonElements(int[] arr1, int[] arr2, int num) {
return Arrays.stream(arr1).anyMatch(x -> x == num) &&
Arrays.stream(arr2).anyMatch(x -> x == num);
}
Similar method using linear search in arrays of Integer using Arrays.asList to convert arrays:
public static boolean findCommonElements(Integer[] arr1, Integer[] arr2, int num) {
return Arrays.asList(arr1).indexOf(num) > -1 &&
Arrays.asList(arr2).indexOf(num) > -1;
}

find the highest product you can get from three of the integers in an array - how to solve using brute force

int arr[] = {10, 10, 1, 3};
Assumptions: Assume every int is positive. Assume array contains at least 3 ints
Find the highest product you can get from three of the integers in the above array. We should return 300 (which we get by taking 10 ∗ 10 ∗ 3).
I want to solve this using brute force method. Basically, I want to multiply each integer by each other integer, and then multiply that product by each other other integer. Can anyone show me how this can be done using nested 3 loops because I want to learn how it's done using brute force first before trying the optimized approach.
Thanks.
Using three for loops :
public static Integer highestProduct(int array[])
{
if((array==null)||(array.length<3))
{
return null;
}
else
{
int max_product = Integer.MIN_VALUE;
for(int i=0;i<array.length;i++)
{
for(int j=i+1;j<array.length;j++)
{
for(int k=j+1;k<array.length;k++)
{
int product = array[i]*array[j]*array[k];
if(product>=max_product)
{
max_product = product;
}
}
}
}
return max_product;
}
}
there are some solutions to ignore brute force.
1. Sort
First you can sort array, it takes O(nlogn) time.
After sorting select last 3 items. As they are highest items, then product will maximum
NOTE: It will not work if there are any negative numbers in your array.
For fixing it you can check some combinations. First calculate first 3 items product, then last 3, then First 2 and Last 1. One of these will be greatest.
2. Dynamic programming
Please see matrix chain multiplication or max growing length problems and dynamic programming solutions for them. It will help you to understand what is dynamic programming and create simple algorithm to solve your problem.

Get max length of row and column in java two dimensional array

What is the best and efficient way to get the maximum i, which is the number of rows and j, which is the number of columns, in a two dimensional array?
Hopefully, the time complexity can be lower than O(n) for every case. No loop here and can still find the maximum j.
For example, if I have an array like this one
[
[18,18,19,19,20,22,22,24,25,26],
[1,2,3],
[0,0,0,0]
]
Then I want to get i = 3 and j = 10 here as a result.
Can anyone help me?
You can avoid writing the loop yourself, but you can't avoid having a runtime of at least O(n), since "someone" needs to loop the source array.
Here is a possible way to do that in Java 8:
Arrays.stream(arr).map(row -> row.length).max(Integer::compare).get();
This returns the maximum length of a "row" in your 2d array:
10
Another version which avoids using the Comparator and therefore might be a bit easier to read:
Arrays.stream(arr).mapToInt(row -> row.length).max().getAsInt();
arr is supposed to be your source array.
Edit: the older version used .max(Integer::max), which is wrong and causes wrong results. See this answer for an explanation.
Assuming your array does not contain null values, you could write something like this:
private static final Comparator<int[]> lengthComparator = new Comparator<int[]> () {
#Override
public int compare(int[] o1, int[] o2) {
return o1.length - o2.length;
}
};
#Test
public void soArrayMaxLength() {
int[][] array = new int[][] {
{18,18,19,19,20, 22, 22, 24, 25,26},
{1,2,3},
{0,0,0,0}
};
int i = array.length;
Optional<int[]> longestArray =
Arrays.stream(array)
.max(lengthComparator);
int j = longestArray.isPresent() ? longestArray.get().length : 0;
System.out.println(String.format("i=%d j=%d", i, j));
}
If you happen to create a parallel stream from the array instead, you could speed up this even further.
Another option is to sort the array by length, the quicksort usually has an average complexity of O(n*log(n)) therefore this isn't faster;
int i = array.length;
Arrays.parallelSort(array, lengthComparator);
int j = array[i-1].length;
System.out.println(String.format("i=%d j=%d", i, j));
Your i is the number of rows, which is simply the length of the 2-D array (assuming you are OK with including empty/null rows in this count).
The max row length j, however, would require iterating over all the rows to find the row i having the maximum arr[i].length.
There will always be a loop1, even though the looping will be implicit in solutions that use Java 8 streams.
The complexity of getting the max number of columns is O(N) where N is the number of rows.
Implicit looping using streams probably will be less efficient than explicit looping using for.
Here's a neat solution using a for loop
int max = o;
for (int i = 0; i < array.length; i++) {
max = Math.max(max, array[i].length);
}
This works in the edge-case where array.length == 0, but if array or any array[i] is null you will get a NullPointerException. (You could modify the code to allow for that, but if the nulls are not expected, an NPE is probably a better outcome.)
1 - In theory, you could unroll the loops for all cases of array.length from 0 to Integer.MAX_VALUE, you would not need a loop. However, the code would not compile on any known Java compiler because it would exceed JVM limits on bytecode segments, etcetera. And the performance would be terrible for various reasons.
You could try this way: loop on the array and find the max length of the arrays which is in this array
byte[][] arrs = new byte[3][];
int maxLength = 0;
for (byte[] array : arrs) {
if (maxLength < array.length) {
maxLength = array.length;
}
}

Why am I getting ArrayIndexOutOfBoundsException?

So I got this assignment while my teacher is away, and basically I have to make a student project. The student has a name, marks, and average. To calculate the average I decided to store the marks inside a int[] array.
public void addQuiz(int m)
{
int l = (marks.length);
marks[l] = m;
}
int[] marks = new int[8];
But when I run the function:
student.addQuiz(90);
I get:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 8
Any help?
I'm not sure what the int[8] part does but it was in the tutorial I followed and it would give me a null pointer without it. There are eight marks in total so I just made it 8.
You can't dynamically add things to an array. You should use an array list instead.
Arraylist<Integer> marks = new ArrayList<Integer>();
then in your addQuiz method:
public void addQuiz(int m) {
marks.add(m)
}
You'll probably also need to change your method for calculating the average a bit, but that should be trivial and I'll leave it to you.
The error says: ArrayIndexOutOfBoundsException: 8
You have an array with 8 elements, indexed from 0 to 7 (inclusive). This array has a length of 8, and you are actually trying to access marks[8], when you only can go up to 7.
In Java, Array index starts from '0'. so, you cannot access the index of the array equal to the length of the array.if your arrays length is '8', then the last index of the array is '7' not '8'. if you are trying to access the illegal index of the array, then ArrayIndexOutOfBoundException is thrown. the code should be changed to
public void addQuiz(int m)
{
int l = (marks.length); //assuming marks is an array of length '8'
marks[l-1] = m; //index is 7 now
}
To calculate the average, you need to sum up the contents of the array (provided all the values are of int values) and then divided by the lenght of the array
int sum = 0;
int avg = 0;
for(int i=0; i<array.length;i++){
sum =sum+array[i];
}
avg = sum/array.length;
Hope this gives an idea
Use Arraylist<Integer> and then you can add to the list dynamically
There is not index in this array for this marks[l] = m;. use marks[l-1] = m;
You can call this for loop in main for getting marks 8 times.
for(int i=0;i<8;i++)
student.addQuiz(<marks you want to enter>, i);
You can define addQuiz function like below
public void addQuiz(int m, int arrayIndex)
{
marks[arrayIndex] = m;
}
int[] marks = new int[8]; //this will be as it is
These are minimal changes. You can make your code better by passing array marks to addQuiz as a parameter. But this will also work, its just that this is not the best way to write code.

Heap Algorithm. Really basic, about array position 0 and 1.

Heap - Sort Algorithm
The problem I am having is this, this algorithms n input is 2, this is designed so that the 1st position (int i) of the array and the 2nd position (int j) have their values compared.
The problem is that this ignores the 0 position of the given array list. I have tried reducing certain values, this will create infinite loops. The algorithm is an adaptation of pseudocode. It isn't designed to run arraylist from 0. I can't think of how to re-adapt this algorithm into a decent minimum heap sort.
public static void input( ArrayList<input> vertexList, int n )
{
int j=n;
int i=n/2;
input object = vertexList.get(n);
while ((i>0) && vertexList.get(i)> object){
vertexList.set(j, vertexList.get(i));
j = i;
i = i/2;
}
vertexList.set(j, object);
}
try to use vertexList.get(i-1) and vertexList.get(j-1) and vertexList.set(j-1, ...)

Categories