Sort a 2d array by the length of subarrays - java

I want to complete the following task:
You get an array of arrays.
If you sort the arrays by their length, you will see, that their length-values are consecutive. But one array is missing! You have to write a method, that return the length of the missing array.
public static int getLengthOfMissingArray(Object[][] arrayOfArrays) {
if (arrayOfArrays.length == 0) { //array empty
return 0;
}
for (int i = 0; i < arrayOfArrays.length; i++) {
//array in the array empty
if (arrayOfArrays[i].length == 0) {
return 0;
}
if (arrayOfArrays[i].length != arrayOfArrays[i + 1].length - 1) {
return arrayOfArrays[i].length + 1;
}
}
return 0;
}
This works for sorted arrays. So I just need a way to order them by their length.
Is there away to sort a 2D array by the (ascending) length of its subarrays?
For example: [[1,2], [1,5,7],[4]] -> [[4], [1,2], [1,5,7]]
Arrays.sort(arr) doesn't work and I get:
Ljava.lang.Object; cannot be cast to java.lang.Comparable

Use this method:
public static int[][] sort(int[][] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = i + 1; j < arr.length; j++) {
if (arr[j].length < arr[i].length) {
// If the length of the array in j less than the
// length of the array in i, replace between them
int[] temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}

You can use Arrays.sort(T[],Comparator) method:
Object[][] arr = {{1, 2}, {1, 5, 7}, {4}};
Arrays.sort(arr, Comparator.comparing(subArr -> subArr.length));
System.out.println(Arrays.deepToString(arr));
// [[4], [1, 2], [1, 5, 7]]
See also: Sort a 2d array by the first column, and then by the second one

Related

How can I find duplicate integers between two arrays and copy them into a new array?

To begin, I am doing this using only arrays (no hash maps or array lists).
I am trying to create a method, project, which inputs two integer arrays with different sizes.
I am trying to compare them in a way to get the following output: projecting [1, 3, 5, 3] to [2, 1, 6, 3, 1, 4, 5, 3] results in: [1, 3, 1, 5, 3].
However, projecting [2, 1, 6, 3, 1, 4, 5, 3] to [1, 3, 5, 3] results in: [1, 3, 5, 3].
I believe the nested for loop might be wrong as it is iterating through the first indices for the first array all the way through the second array, then going to the next.
I'm getting an ArrayIndexOutOfBoundsException for the starred line (tempArray[i] == arr1[i], I know it shouldn't be tempArray[i] but not sure what exactly to put).
I'm not sure how to compare them in a way to produce the line above, as it needs to be "in order". What could be the best way to accomplish this?
I attempted the following code:
public int[] project(int[] arr1, int[] arr2) {
int counter = 0;
for (int i = 0; i < arr1.length; i++) {
for (int j = 0; j < arr2.length; j++) {
if (arr1[i] == arr2[j]) {
counter++;
}
}
}
int[] tempArray = new int[counter];
for(int i = 0 ; i < arr1.length; i++) {
for (int j = 0; j < arr2.length; j++) {
if(arr1[i] == arr2[j]) {
tempArray[i] = arr1[i]; // UNDERLINED
}
}
}
}
Edit
The ArrayIndexOutOfBounds error is gone, but now my return statement is: projecting [1, 3, 5] to [2, 1, 6, 3, 1, 4, 5, 3] results in: [1, 3, 5, 0, 0], when it needs to be: projecting [1, 3, 5] to [2, 1, 6, 3, 1, 4, 5, 3] results in: [1, 3, 1, 5, 3].
Any idea what is causing this issue?
I think you have a typo in your first for loop
change this to later
arr1[i] == arr2[i]
to
arr1[i] == arr2[j]
Regarding overlapping issues in the projection array, you need to maintain different value as your index rather than i or j which is used by arr1 and arr2 respectively
int[] tempArray = new int[counter];
int index = 0;
for(int i=0 ; i < arr1.length; i++) {
for (int j=0; j < arr2.length; j++) {
if(arr1[i] == arr2[j]) {
tempArray[index++] = arr1[i];
}
}
}
For the values which you are expecting you should loop through arr2 first
for(int j=0 ; j < arr2.length; j++) {
for (int i=0; i < arr1.length; i++) {
if(arr1[i] == arr2[j]) {
tempArray[index++] = arr1[i];
}
}
}
If the contents of array are not hardcoded and you dont know the order in which you want to pass, you can make use of length
int[] ans;
if(a.length < b.length) {
ans = project(a, b);
} else {
ans = project(b, a);
}
Output:
[1, 3, 1, 5, 3]
You currently have index variables (i, j) tracking the indexes of each input array as you loop through them, but you also need to keep track of the write head of the result array. Initialize, say int k = 0 before the outer for loop, then set the value like this: tempArray[k++] = array1[i];.
You can forgo the first loop If you are OK with performing a single array copy. Initialize an array as long as the second input array (since there can never be more duplicated elements than existing elements) as the tempArray. Then if you want it to fit exactly, initialize the final array to the exact length k and use System#arrayCopy.
this will probably solve your problem
public int[] project(int[] arr1, int[] arr2) {
int counter = 0;
for (int i : arr2) {
if (Arrays.binarySearch(arr1, i) >= 0) {
counter++;
}
}
int[] arr4 = new int[counter];
int index = 0;
for (int i : arr2) {
if (Arrays.binarySearch(arr1, i) >= 0) {
arr4[index++] = i;
}
}
return arr4;
}
The nested iteration is expensive, so we want to avoid that. The first thing to do is sort the array we are projecting from so we can perform a binary search on it. Second, don't execute the nested iteration to determine the output array size. Create an array the size of the array we are projecting to since it can be no longer than that.
public int[] projection(int[] a, int[] b) {
int[] temp = new int[b.length];
int nextIndex = 0;
for (int x : b) {
if (contains(a, x)) {
temp[nextIndex++] = x;
}
}
return slice(temp, nextIndex);
}
private boolean contains(int[] array, int value) {
for (int element : array) {
if (element == value) {
return true;
}
}
return false;
}
private int[] slice(int[] src, int size) {
int[] slice = new int[size];
for (int index = 0 ; index < size ; ++index) {
slice[index] = src[index];
}
return slice;
}
For your second problem, I think, in your temporary array, you should be saving the values from arr2[j] instead of arr1[i].
Also, you need a different counter (set to 0 initially and incremented in the loop) for setting the values in tempArray[counter].
What I mean exactly is:
int counter = 0;
for (int i = 0; i < arr1.length; i++) {
for (int j = 0; j < arr2.length; j++) {
if (arr1[i] == arr2[j]) {
tempArray[counter] = arr2[j];
counter++;
}
}
}

Checking if two int arrays have duplicate elements, and extract one of the duplicate elements from them

I'm trying to write a method, union(), that will return an int array, and it takes two int array parameters and check if they are sets, or in other words have duplicates between them. I wrote another method, isSet(), it takes one array argument and check if the array is a set. The problem is I want to check if the two arrays in the union method have duplicates between them, if they do, I want to extract one of the duplicates and put it in the unionArray[] int array. This is what I tried so far.
public int[] union(int[] array1, int[] array2){
int count = 0;
if (isSet(array1) && isSet(array2)){
for (int i = 0; i < array1.length; i++){
for (int j = 0; j < array2.length; j++){
if (array1[i] == array2[j]){
System.out.println(array2[j]);
count ++;
}
}
}
}
int[] array3 = new int[array2.length - count];
int[] unionArray = new int[array1.length + array3.length];
int elementOfUnion = 0;
for (int i = 0; i< array1.length; i++){
unionArray[i] = array1[i];
elementOfUnion = i + 1 ;
}
int index = 0;
for (int i = elementOfUnion; i < unionArray.length; i++){
unionArray[i] = array3[index];
index++;
}
return unionArray;
}
public boolean isSet(int[] array){
boolean duplicates = true;
for (int i = 0; i < array.length; i++){
for(int n = i+1; n < array.length; n++){
if (array[i] == array[n])
duplicates = false;
}
}
return duplicates;
}
What I was trying to do is to use all of array1 elements in the unionArray, check if array2 has any duplicates with array1, and then move all the non-duplicate elements from array2 to a new array3, and concatenate array3 to unionArray.
It will be much easier to do it with Collection API or Stream API. However, you have mentioned that you want to do it purely using arrays and without importing any class, it will require a few lengthy (although simple) processing units. The most important theories that drive the logic is how (given below) a union is calculated:
n(A U B) = n(A) + n(B) - n(A ∩ B)
and
n(Only A) = n(A) - n(A ∩ B)
n(Only B) = n(B) - n(A ∩ B)
A high-level summary of this solution is depicted with the following diagram:
Rest of the logic has been very clearly mentioned through comments in the code itself.
public class Main {
public static void main(String[] args) {
// Test
display(union(new int[] { 1, 2, 3, 4 }, new int[] { 3, 4, 5, 6 }));
display(union(new int[] { 1, 2, 3 }, new int[] { 4, 5, 6 }));
display(union(new int[] { 1, 2, 3, 4 }, new int[] { 1, 2, 3, 4 }));
display(union(new int[] { 1, 2, 3, 4 }, new int[] { 3, 4 }));
display(union(new int[] { 1, 2, 3, 4 }, new int[] { 4, 5 }));
display(union(new int[] { 1, 2, 3, 4, 5, 6 }, new int[] { 7, 8 }));
}
public static int[] union(int[] array1, int[] array2) {
// Create an array of the length equal to that of the smaller of the two array
// parameters
int[] intersection = new int[array1.length <= array2.length ? array1.length : array2.length];
int count = 0;
// Put the duplicate elements into intersection[]
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array2.length; j++) {
if (array1[i] == array2[j]) {
intersection[count++] = array1[i];
}
}
}
// Create int []union of the length as per the n(A U B) = n(A) + n(B) - n(A ∩ B)
int[] union = new int[array1.length + array2.length - count];
// Copy array1[] minus intersection[] into union[]
int lastIndex = copySourceOnly(array1, intersection, union, count, 0);
// Copy array2[] minus intersection[] into union[]
lastIndex = copySourceOnly(array2, intersection, union, count, lastIndex);
// Copy intersection[] into union[]
for (int i = 0; i < count; i++) {
union[lastIndex + i] = intersection[i];
}
return union;
}
static int copySourceOnly(int[] source, int[] exclude, int[] target, int count, int startWith) {
int j, lastIndex = startWith;
for (int i = 0; i < source.length; i++) {
// Check if source[i] is present in intersection[]
for (j = 0; j < count; j++) {
if (source[i] == exclude[j]) {
break;
}
}
// If j has reached count, it means `break;` was not executed i.e. source[i] is
// not present in intersection[]
if (j == count) {
target[lastIndex++] = source[i];
}
}
return lastIndex;
}
static void display(int arr[]) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
System.out.print(i < arr.length - 1 ? arr[i] + ", " : arr[i]);
}
System.out.println("]");
}
}
Output:
[1, 2, 5, 6, 3, 4]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 5, 4]
[1, 2, 3, 4, 5, 6, 7, 8]
Using Java's streams could make this quite simpler:
public int[] union(int[] array1, int[] array2) {
return Stream.of(array1, array2).flatMapToInt(Arrays::stream).distinct().toArray();
}
Even with all the restrictions of only using arrays, you can simplify your code a lot. No need to check for sets. Just :
allocate an array to store all elements of the union (i.e., int[] tmp_union ), which at worst will be all elements from both arrays array1 and array2.
iterate over the elements of array1 and compared them against the elements from tmp_union array, add them into the tmp_union array only if they were not yet added to that array.
Repeat 2) for the array2.
During this process keep track of the number of elements added to the tmp_union array so far (i.e., added_so_far). In the end, copy the elements from the tmp_union array into a new array (i.e., unionArray) with space allocated just for the union elements. The code would look something like:
public static int[] union(int[] array1, int[] array2){
int[] tmp_union = new int[array1.length + array2.length];
int added_so_far = add_unique(array1, tmp_union, 0);
added_so_far = add_unique(array2, tmp_union, added_so_far);
return copyArray(tmp_union, added_so_far);
}
private static int[] copyArray(int[] ori, int size) {
int[] dest = new int[size];
for(int i = 0; i < size; i++)
dest[i] = ori[i];
return dest;
}
private static int add_unique(int[] array, int[] union, int added_so_far) {
for (int element : array)
if (!is_present(union, added_so_far, element))
union[added_so_far++] = element;
return added_so_far;
}
private static boolean is_present(int[] union, int added_so_far, int element) {
for (int z = 0; z < added_so_far; z++)
if (element == union[z])
return true;
return false;
}

Sorting array contains some arrays in java

I have a array that contains arrays in it.
and I need to write a function that sort the little array on the big array( I mean the minimum sum of the little array is be the first on the index 0 and after the second on index1 and the maximum sum of the little array in in the end of the big aray =index bigArray.length-1
How can I sort an array that contains arrays in it?
i need to do that with no object or things like that. just regular and simple code.
enter image description here
public static int [][] sum (int [][] arr) {
int sum=0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length; j++) {
sum=sum+arr[i][j];
}
Since summing the inner array is a relatively time-consuming process, and the sum value is needed more than once when sorting, you should create an object to hold the array and the sum, e.g.
static class ArraySum implements Comparable<ArraySum> {
final int[] array;
final int sum;
ArraySum(int[] array) {
this.array = array;
this.sum = Arrays.stream(array).sum();
}
#Override
public int compareTo(ArraySum that) {
return Integer.compare(this.sum, that.sum);
}
}
Since it's Comparable, you can sort it directly, so with that in hand, you can easily sort the outer array using Java 8+ streams:
public static int[][] sort(int[][] arr) {
return Arrays.stream(arr).map(ArraySum::new).sorted()
.map(a -> a.array).toArray(int[][]::new);
}
That doesn't sort the input 2D array, but returns a new 2D array, i.e. a new outer array with the original inner arrays sorted.
Test
int[][] arr = { { 3, 5, 4 }, { 4, 3, 1, 2 }, { 5, 6 } };
int[][] arr2 = sort(arr);
System.out.println(Arrays.deepToString(arr));
System.out.println(Arrays.deepToString(arr2));
Output
[[3, 5, 4], [4, 3, 1, 2], [5, 6]]
[[4, 3, 1, 2], [5, 6], [3, 5, 4]]
// 10 11 12 sum
As you can see, the original 2D array is unmodified, and the new array is sorted by the sum of the inner arrays.
I don't think this works perfectly, but it should definitely get you close. I believe this is a buble sort technique.
public static int [][] sum (int [][] arr) {
//start at first array
for (int i = 0; i < arr.length - 1; i++) {
//sum of first array
int sum1 = 0;
for (int j = 0; j < arr[i].length; j++){
sum1 += arr[i][j];
}
//compare to each of the arrays after
for (int k = i+1; k < arr.length; k++) {
int sum2 = 0;
for (int l = 0; l < arr[k].length; j++){
sum2 += arr[k][l];
}
//if second array is smaller, swap
if (sum2 < sum1){
//might need to change this part to do complete copy
temp = arr[i];
arr[i] = arr[k];
arr[k] = temp;
}
}
}
return arr
}

Add up each element in two uneven arrays in Java

Im Swedish so maybe I did give the wrong title.
I have two arrays of different size:
{2, 5, 10, 13}
{5, 7, 5, 22, 44, 75}
I want to add each element and put it in a third array.
So the result should be {7, 12, 15, 25, 44, 75}
I have manage to done some code.
I get an exeption of out of bounds.
I think the problem is that I can´t add a non existing element.
But how can I solve it?
public static void main(String[] args) {
int[] samling = {1, 2, 4, 3, 8};
int[] samling2 = {1, 2, 4, 3, 8, 8, 3};
int[] svar = concateArrays(samling, samling2);
for(int i=0; i < svar.length; i++)
System.out.println("Ny Array " + svar[i]);
}
public static int[] concateArrays(int[] samling, int[] samling2)
{
int sum = samling.length + samling2.length;
int[] total = new int[sum];
for(int i=0; i < total.length; i++){
//if (samling2.length != 0) // || samling.length != 0)
total[i] = samling[i] + samling2[i];
}
return total;
}
The length of the output array shouldn't be the sum of lengths of the input arrays, it should be the length of the longer input array. And before accessing an element of either input array, you must check the current index i is a valid index of that array.
public static int[] concateArrays(int[] samling, int[] samling2)
{
int[] total = new int[Math.max(samling.length,samling2.length)];
for(int i=0; i < total.length; i++) {
total[i] = (i < samling.length ? samling[i] : 0) +
(i < samling2.length ? samling2[i] : 0);
}
return total;
}
You can use one loop to loop over both arrays simultaneously.
You first need to check which array is the longest, and make a new array:
int[] arr = new int[longest];
Then you need to walk over the array. In this example, I assume the latter array is always the longest.
for (int i = 0; i < samling2.length; i++) {
int totalValue = samling[i];
if (i < samling.length) {
totalValue += samling2[i];
}
arr[i] = totalValue;
}
You can make an array of length equal to max of the two arrays you have. Then you can add the elements from both arrays if the specific index exist in both arrays else simply copy the index from the array which contain that index.
See the following code to get a better picture
import java.io.*;
class GFG {
public static void main(String[] args) {
int[] samling = {1, 2, 4, 3, 8};
int[] samling2 = {1, 2, 4, 3, 8, 8, 3};
int[] svar = concateArrays(samling, samling2);
System.out.println("Ny Array :");
for(int i=0; i < svar.length; i++)
System.out.print(svar[i] + " ");
}
public static int[] concateArrays(int[] samling, int[] samling2)
{
int len = 0;
if (samling.length > samling2.length)
len = samling.length;
else
len = samling2.length;
int[] total = new int[len];
for(int i=0; i < len; i++){
if (i >= samling2.length) {
total[i] = samling[i];
}else if( i >= samling.length) {
total[i] = samling2[i];
}else{
total[i] = samling2[i] + samling[i];
}
}
return total;
}
}
Another variant, with no need for a conditional operation in each iteration of the copying loop:
public static int[] concateArrays(int[] samling, int[] samling2)
{
// max length of the two arrays
int maxLen = Math.max(samling.length,samling2.length);
// decide which of the inputs is shorter and which is longer
int[] shorter = maxLen == samling.length ? samling2 : samling;
int[] longer = maxLen == samling.length ? samling : samling2;
int[] total = new int[maxLen];
// add both as long as there are elements in the shorter
for(int i=0; i < shorter.length; i++) {
total[i] = shorter[i] + longer[i];
}
// copy the remainder of the longer
for(int i=shorter.length; i < longer.length; i++) {
total[i] = longer[i];
}
return total;
}
You can try this :
public static int[] concateArrays(int[] samling, int[] samling2)
{
int minLength = samling.length;
int[] array = null;
if (samling2.length > samling.length) {
array = samling2;
} else {
minLength = samling2.length;
array = samling;
}
for (int i = 0; i < minLength; i++) {
array[i] = samling[i] + samling2[i];
}
return array;
}

compare two arrays for common Items and return another array with the common items

So the problem is I have two array and have to check them for common items.Usual stuff, very easy.But the tricky thing for me is that I have to return another array with the elements that have been found to be common.I cannot not use any Collections.Thanks in advance.This is my code so far!
public class checkArrayItems {
static int[] array1 = { 4, 5, 6, 7, 8 };
static int[] array2 = { 1, 2, 3, 4, 5 };
public static void main(String[] args) {
checkArrayItems obj = new checkArrayItems();
System.out.println(obj.checkArr(array1, array2));
}
int[] checkArr(int[] arr1, int[] arr2) {
int[] arr = new int[array1.length];
for (int i = 0; i < arr1.length; i++) {
for (int j = 0; j < arr2.length; j++) {
if (arr1[i] == arr2[j]) {
arr[i] = arr1[i];
}
}
}
return arr;
}
}
In case someone was wondering how the "chasing" algorithm mentioned by #user3438137 looks like:
int[] sorted1 = Arrays.copyOf(array1, array1.length);
Arrays.sort(sorted1);
int[] sorted2 = Arrays.copyOf(array2, array2.length);
Arrays.sort(sorted2);
int[] common = new int[Math.min(sorted1.length, sorted2.length)];
int numCommonElements = 0, firstIndex = 0; secondIndex = 0;
while (firstIndex < sorted1.length && secondIndex < sorted2.length) {
if (sorted1[firstIndex] < sorted2[secondIndex]) firstIndex++;
else if (sorted1[firstIndex] == sorted2[secondIndex]) {
common[numCommonElements] = sorted1[firstIndex];
numCommonElements++;
firstIndex++;
secondIndex++;
}
else secondIndex++;
}
// optionally trim the commonElements array to numCommonElements size
You can use a MIN or MAX default dummy value for the elements in your new array arr using arr[i] = Integer.MIN_VALUE;. In that way you will be able to differentiate between the real and dummy values. Like below:
int[] checkArr(int[] arr1, int[] arr2) {
int[] arr = new int[array1.length];
for (int i = 0; i < arr1.length; i++) {
arr[i] = Integer.MIN_VALUE;
for (int j = 0; j < arr2.length; j++) {
if (arr1[i] == arr2[j]) {
arr[i] = arr1[i];
}
}
}
return arr;
}
Output
[4, 5, -2147483648, -2147483648, -2147483648]
EDIT
Conclusion
When you iterate over arr all the values other than -2147483648 are common.
EDIT 2
To print the common values as mentioned on the comment below:
public static void main(String[] args) {
checkArrayItems obj = new checkArrayItems();
int[] arr = obj.checkArr(array1, array2);
System.out.println("Common values are : ");
for (int x : arr) {
if (x != Integer.MIN_VALUE) {
System.out.print(x+"\t");
}
}
}
Suggestion: Follow naming convention for class i.e. make checkArrayItems to CheckArrayItems.
I'm lazy to type the code, but here is the algorithm.
1. sort both array
2. iterate over array comparing items and increasing the indexes.
Hope this helps.
Declare an index before the two for loops
int index = 0;
that will hold the current position of the arr array. Then:
arr[index++] = arr1[i];
And also, since you initialize arr with arr1.lenght your array will be filled with 0s at the end of the not colision.

Categories