Given the following two dimensional array
int[][] arr = {{1, 2}, {3, 4}, {5, 6}};
How can I flatten it column-by-column using the Java 8 Stream API? I want to get:
int[] result = {1, 3, 5, 2, 4, 6};
I tried doing a simple flatMap, but this flattens row-by-row and results in the wrong order:
// result is { 1, 2, 3, 4, 5, 6 }
int[] result = Arrays.stream(arr)
.flatMapToInt(Arrays::stream)
.toArray();
I considered transposing the array first so that I can use the above snippet, but creating an intermediate, transposed copy of the array seems unnecessary. How can I flatmap by column directly?
It can be assumed that all the nested arrays are of same length.
You can stream the inner indexes and flatMap to each outer array:
IntStream.range(0, arr[0].length)
.flatMap(i -> Arrays.stream(arr).mapToInt(a -> a[i]))
.toArray()
If we assume that all the nested arrays are of the same length we can use nested loops:
int[][] arr = {{1, 2}, {3, 4}, {5, 6}};
int[] res = new int[arr.length * arr[0].length];
int j = 0;
for (int i = 0; i < arr[0].length; i++) {
for (int[] a : arr) {
res[j++] = a[i];
}
}
System.out.println(Arrays.toString(res)); // [1, 3, 5, 2, 4, 6]
This is another way to do it:
int[][] nestedArray = {{1, 12, 2}, {1, 13, 11, 5, 16}, {7, 8, 9}};
LinkedList<Integer> theList = new LinkedList<>();
for(int[] sList: nestedArray) {
stream(sList)
.forEach(theList::add);
}
theList.stream()
.forEach(e ->System.out.println(e));
I revised the previous code to more KISS and readable.
int[][] nestedArray = {{3, 4, 5, 6}, {1, 2}, {7, 8, 9}};
LinkedList<Integer> theList = new LinkedList<>();
for(int[] sList: nestedArray) {
stream(sList)
.forEach(theList::add);
}
theList.stream()
.forEach(e ->System.out.println(e));
Related
I am new to java 8. Just wondering how would I do below operation using java 8 streams. Any suggestions
public static void main(String[] args) {
Integer[] arr1 = new Integer[]{1, 2, 3};
Integer[] arr2 = new Integer[]{4, 5, 6};
Integer[] arr3 = new Integer[]{7, 8, 9};
for(int i=0; i<arr1.length; i++){
System.out.println(listFromIndex(arr1[i], arr2[i], arr3[i]));
}
}
private static List<Integer> listFromIndex(Integer e, Integer e1, Integer e2) {
List<Integer> list = new ArrayList<>();
list.add(e) ;
list.add(e1) ;
list.add(e2) ;
return list;
}
Output :
[1, 4, 7]
[2, 5, 8]
[3, 6, 9]
Assuming the arrays are of the same length, you can do it as:
IntStream.range(0, arr1.length)
.mapToObj(i -> listFromIndex(arr1[i], arr2[i], arr3[i]))
.forEach(System.out::println);
If all of the arrays have the same length you can use this:
List<Integer[]> arrays = Arrays.asList(arr1, arr2, arr3);
IntStream.range(0, arr1.length)
.mapToObj(i -> arrays.stream().map(a -> a[i]).collect(Collectors.toList()))
.forEach(System.out::println);
This creates a list containing all arrays. After that it creates a stream iterating over all arrays and collects the new arrays.
This will print the following result:
[1, 4, 7]
[2, 5, 8]
[3, 6, 9]
If you have arrays with different lengths you can use something like this:
Integer[] arr1 = new Integer[]{1, 2, 3};
Integer[] arr2 = new Integer[]{4, 5};
Integer[] arr3 = new Integer[]{7};
List<Integer[]> arrays = Arrays.asList(arr1, arr2, arr3);
IntStream.range(0, arrays.stream().mapToInt(a -> a.length).max().orElseThrow())
.mapToObj(i -> arrays.stream().map(a -> i < a.length ? a[i] : null).collect(Collectors.toList()))
.forEach(System.out::println);
This uses the length of the largest array and checks i before collecting the resulting arrays.
The result will be this:
[1, 4, 7]
[2, 5, null]
[3, null, null]
I am creating a program with a method whose input is an 2D array of int, that checks to see if arrays are Latin Squares.
For example a Latin Square would look like this:
1 2 3
2 3 1
3 1 2
This is my code so far:
public class LatinSquare {
public boolean isLatinSquare(int[][] a){
int[] row= new int[a.length];
int[] column = new int[a[0].length];
for (int j = 0; j<column.length; j++){
for (int i = 0; i<row.length;i++){
row[i] = a[i][j];
}
for (int i = 0; i<row.length -1; i++){
for (int x= i+1; x<=row.length;x++){
if (row[i]==row[x])
return false;
}
}
}
}
The code is not fully complete but I just wanted to know if someone could answer some questions before I head in the wrong direction if I am doing something wrong.
My Question: Is this the best approach for checking arrays to see if they would fulfill a Latin Square? My thought process is that I start at column '0' and then go through the row comparing each number to each other making sure they are not equal, and move through each column this way. Is this the wrong way to be approaching this?
Lots of nested loops will degrade performance. Here is a faster version, but it uses a bit more memory.
It relies on the values of the square being in the range 1 to N, where N is the square size.
private static boolean isLatinSquare(int[][] square) {
boolean[][] foundInRow = new boolean[square.length][square.length];
boolean[][] foundInCol = new boolean[square.length][square.length];
for (int row = 0; row < square.length; row++) {
if (square[row].length != square.length)
return false; // Not a square
for (int col = 0; col < square.length; col++) {
int idx = square[row][col] - 1;
if (foundInRow[row][idx] || foundInCol[col][idx])
return false;
foundInRow[row][idx] = foundInCol[col][idx] = true;
}
}
return true;
}
Test
System.out.println(isLatinSquare(new int[][] { {1, 2, 3},
{2, 3, 1},
{3, 1, 2} }));
System.out.println(isLatinSquare(new int[][] { {1, 2, 3},
{3, 1, 2},
{2, 3, 1} }));
System.out.println(isLatinSquare(new int[][] { {1, 3, 2},
{2, 1, 3},
{3, 2, 1} }));
System.out.println(isLatinSquare(new int[][] { {1, 3, 2},
{3, 2, 1},
{2, 1, 3} }));
System.out.println(isLatinSquare(new int[][] { {1, 3, 2},
{3, 2, 1},
{1, 3, 2} }));
System.out.println(isLatinSquare(new int[][] { {1, 3, 1},
{3, 2, 3},
{2, 1, 2} }));
System.out.println(isLatinSquare(new int[][] { {1, 2, 3},
{2, 3},
{3, 1, 2} }));
Output
true
true
true
true
false
false
false
I am trying to write a code that finds the average of the inputs of a 2D array:
This is what I have written:
public class AverageLength
{
public static void main(String[] args)
{
int sum = 0;
int w = 0;
int[][] foobar = new int[][]
{
{0, 5, 7},
{3, 2, 4},
{8, 7, 3},
{1, 5, 3}
};
for (int i = 0; i < foobar.length; i++)
{
for (int j = 0; j <foobar[0].length; j++)
{
System.out.println(foobar[i][j]);
sum = sum + foobar[i][j];
w++;
}
} System.out.println("Average = " + sum/w);
}
}
However, if I change the array lengths and try what follows:
int[][] foobar = new int[][]
{
{0, 5, 7, 3},
{3, 3, 5, 7, 8, 4},
{8, 3},
{1, 5, 1, 2, 3}
};
it gives me the following error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
at AverageLength.main(AverageLength.java:18)
How can I fix this issue?
change
foobar[0].length
to
foobar[i].length
when your sub arrays lengths are different you should get corresponding length
for example
{0, 5, 7, 3},
{3, 3, 5, 7, 8, 4},
{8, 3},
in this case
foobar[0].length is 4 .so when you loop through 3rd sub array {8, 3}
and when you try to access 2nd index [3rd element ] you get error
ArrayIndexOutOfBoundsException: 2
because there is no 2nd index.
and also in 2nd sub array {3, 3, 5, 7, 8, 4}, value 8 and 4 will not print because you loop 4 times .
When you check in your seccond for for array length you should use i not 0, because if you use 0 you will always get length of just first array.
for (int j = 0; j <foobar[i].length; j++)
By using foobar[0].length you are using the length of the first inner array for every inner array. Use foobar[i].length instead, which will calculate the current array's length.
By the way: Calculating averages of int arrays can be done java-internally since Java8. An example of how to use Java8's streaming API to solve this task:
import java.util.Arrays;
public class AverageLength
{
public static void main(String[] args)
{
int[][] foobar = new int[][]
{
{0, 5, 7},
{3, 2, 4},
{8, 7, 3},
{1, 5, 3}
};
System.out.print("Average = ");
System.out.println(
// convert 2D array to stream of arrays
Arrays.stream(foobar)
// flatten 2D array to 1D array
.flatMapToInt(Arrays::stream)
// let java calculate the average
.average()
// get result
.getAsDouble());
}
}
Benefits:
code is easier to understand
your program is potentially much faster
code can be easily changed to run in several threads (use .parallel())
If I have an array:
int[] myArray = new int[10]
for (int i = 0; i < myArray.length; i++) {
myArray[i] = i;
}
//resulting array: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
How can I move everything behing the 4 up one space, and send the 4 to the back? Example:
this:
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
into this:
{0, 1, 2, 3, 5, 6, 7, 8, 9, 4}
How about this:
int[] myArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
System.arraycopy(myArray, 5, myArray, 4, 5);
myArray[myArray.length-1] = 4;
In the above code, I'm using the arraycopy method to copy a range of 5 numbers starting from index 5, to index 4 in the array, and then simply set a 4 in the last position.
Notice that using arraycopy is much faster than copying the values in a loop, since it's usually implemented as a native operation which copies memory positions.
EDIT :
A more generic solution, a method for sending to the back a given position in the array:
public static void sendBack(int[] array, int idx) {
int value = array[idx];
System.arraycopy(array, idx+1, array, idx, array.length-idx-1);
array[array.length-1] = value;
}
For your example, call it like this:
sendBack(myArray, 4);
// now myArray is {0, 1, 2, 3, 5, 6, 7, 8, 9, 4}
Like this?
int start = 4;
int temp = myArray[start];
for(int i = start; i < myArray.length - 1; i++) {
myArray[i] = myArray[i+1];
}
myArray[myArray.length-1] = temp;
It's the fastest way I can guess...
Use System.arraycopy.
Let's say I have an array:
int array[][] = {{1, 2, 3}, {2, 5, 7}, {4, 2, 1}};
How can I randomly make it
int array[][] = {{2, 5, 7}, {1, 2, 3}, {4, 2, 1}};
or
int array[][] = {{4, 2, 1}, {2, 5, 7}, {1, 2, 3},};
And so on.
Is there any JAVA function to help me? Or I have to figure it out by myself?
Thank you.
You might convert your array to a List<int[]> and call Collections.shuffle(). Then convert back to an array.
int array[][] = {{1, 2, 3}, {2, 5, 7}, {4, 2, 1}};
List<int[]> l = Arrays.asList( array ); //the list returned is backed by the array, and thus the array is shuffled in place
Collections.shuffle( l );
//no need to convert back
If you need to keep the original order, you'd have to create a copy of the array (or the list backed by that array), like this:
int array[][] = {{1, 2, 3}, {2, 5, 7}, {4, 2, 1}};
List<int[]> l = new ArrayList<int[]>( Arrays.asList( array ) ); //creates an independent copy of the list
Collections.shuffle( l );
int newArray[][] = l.toArray( new int[0][0] );
Another way:
int array[][] = {{1, 2, 3}, {2, 5, 7}, {4, 2, 1}};
int newArray[][] = array.clone(); //copy the array direcly
List<int[]> l = Arrays.asList( newArray );
Collections.shuffle( l );
It is very simple using the Collections.shuffle(..) method as the Arrays.asList(..) method returns a List backed by the array.
Collections.shuffle(Arrays.asList(array));
Full example:
public static void main(String... args) {
int array[][] = {{1, 2, 3}, {2, 5, 7}, {4, 2, 1}};
Collections.shuffle(Arrays.asList(array));
for (int[] a : array)
System.out.println(Arrays.toString(a));
}
If you can use collections there is a shuffle method, if you have to use a primitive type such as int, you will have to shuffle it yourself. Here are examples of both:
http://blog.ryanrampersad.com/2008/10/13/shuffle-an-array-in-java/
Try the Collections class that comes with Java. You can use the shuffle() method to randomize the indices to access the arrays.
Link to Java API
Use Collections:
something like this:
List<int[]> list = Arrays.asList(array);
Collections.shuffle(list);
int[][] shuffledArray = (int[][]) shuffledList.toArray();
What you want is random swaps of the contents of the outer array.
You could use java.Random's nextBoolean() to get a true/false as to whether to make a swap, such as between 1&2 or 1&3 or 2&3.
This is assuming you want to work with the primitive types, and not classes.