How to seperate even and odd numbers in the same array? - java

How would I separate even and odd integers in an array with order preserved?
Modifications must be in place and the return is a void, and can only use built in methods.
An example would be:
{4, 5, 8, 16, 45, 12, 67, 13} -> {4, 8, 16, 12, 5, 45, 67, 13}

Explanation
You can easily solve this with one iteration, remembering the index of the current border and swapping elements.
So for your example, the process will be:
{ 4, 5, 8, 16, 45, 12, 67, 13 } // swap 4 with 4
^
{ 4, 5, 8, 16, 45, 12, 67, 13 }
^
{ 4, 8, 5, 16, 45, 12, 67, 13 } // swap 5 with 8
^
{ 4, 8, 16, 5, 45, 12, 67, 13 } // swap 5 with 16
^
{ 4, 8, 16, 12, 45, 5, 67, 13 } // swap 5 with 12
^
Where the ^ shows the current border index, which is always one ahead of the even values, pointing at the index where you want to swap the next even value to.
First draft
Here is the code for that:
int borderIndex = 0;
for (int i = 0; i < values.length; i++) {
int value = values[i];
if (value % 2 == 0) {
// swap
values[i] = values[borderIndex];
values[borderIndex] = value;
borderIndex++;
}
}
Preserving order
Now, this solution already preserves the order of the even numbers out of the box. But if you pay close attention you see that it does not preserve order of the odd values. It goes wrong as soon as you have multiple odd values after each other before an even value, like
..., 5, 45, 12, ...
because it will then swap 5 with 12 resulting in 12, 45, 5 instead of 12, 5, 45.
Even worse when there are multiple odd values:
..., 5, 7, 9, 11, 12, ...
resulting in 12, 7, 9, 11, 5.
In order to fix this, we have to not just swap 5 with the even value 12 but actually swap all the way back to 5. So:
swap 12 with 11
swap 12 with 9
swap 12 with 7
swap 12 with 5
basically shifting down 12 from right to left, until it stands right in front of 5.
We can do so easily with a simple loop that moves from 12 (at i) to 5 (at borderIndex):
int borderIndex = 0;
for (int i = 0; i < values.length; i++) {
int value = values[i];
if (value % 2 == 0) {
// swap from i to borderIndex
for (int j = i; j > borderIndex; j--) {
values[j] = values[j - 1];
values[j - 1] = value;
}
borderIndex++;
}
}

You can also do it like this. In this case your sorting them on their inherent nature as opposed to their relationship to each other.
Integer [] arr = {4, 5, 8, 16, 45, 12, 67, 13};
Arrays.sort(arr, Comparator.comparing(a->a % 2));
System.out.println(Arrays.toString(arr));
prints
[4, 8, 16, 12, 5, 45, 67, 13]

Related

Calculating List of cumulative sums from List of integers with Java streams

I have the following list :
INPUT :: 4 5 8 -11 9 5 -7 4 6 -6 -8 -11 80 -32 -56 -15 5 -49
OUTPUT :: 4 9 17 6 15 20 13 17 23 17 9 -2 78 46 -10 -25 -20 -69
I need to calculate cumulative sum - List meaning
T(n) = T(n) + T(n-1) for n >0;
and
T(0) = T(0)
I want to calculate that with Java stream API so that I can implement it with Spark for big data calculation. I am naive in Java Streams I have tried several expressions bt none of them is working
the equivalent stuctured code should be like :
int[] numbers = {4, 5, 8, -11, 9, 5, -7, 4, 6,-6, -8, -11, 80, -32, -56, -15, 5, -49};
int temp = 0;
for (int i = 0 ; i < numbers.length ; i++) {
temp = temp + numbers[i];
numbers[i] = temp;
}
Try this.
int[] a = {4, 5, 8, -11, 9, 5, -7, 4, 6, -6, -8, -11, 80, -32, -56, -15, 5, -49};
Arrays.parallelPrefix(a, (x, y) -> x + y);
System.out.println(Arrays.toString(a));
output:
[4, 9, 17, 6, 15, 20, 13, 17, 23, 17, 9, -2, 78, 46, -10, -25, -20, -69]
Here are two ways of doing it.
The first is very inefficient as it basically uses nested loops to accumulate the values. The first IntStream specfies the range of values and the nested IntStream creates a variable range and sums up the values from 0 to the end of that range.
int[] result1 = IntStream.range(0, vals.length).map(
i -> IntStream.rangeClosed(0, i).map(k->vals[k]).reduce(0, (a, b) -> a + b))
.toArray();
This one is more in line with a more conventional method. Stream a single array of 0 and then use that to accumulate a running sum of the values.
int[] result2 = Stream.of(new int[] { 0 })
.flatMapToInt(k -> IntStream.of(vals).map(v -> {
k[0] += v;
return k[0];
})).toArray();
System.out.println(Arrays.toString(result1));
System.out.println(Arrays.toString(result2));
Both print
[4, 9, 17, 6, 15, 20, 13, 17, 23, 17, 9, -2, 78, 46, -10, -25, -20, -69]
[4, 9, 17, 6, 15, 20, 13, 17, 23, 17, 9, -2, 78, 46, -10, -25, -20, -69]
But you simply can't do any better than this.
for (int i = 1; i < vals.length; i++) {
vals[i] += vals[i-1];
}
Bottom line is to stick with what you have.
You can try using a custom collector.
public static void main(String[] args) {
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> cumulatives = integers.stream().collect(CumulativeAdd.collector());
}
private static final class CumulativeAdd {
List<Integer> retArray= new ArrayList<>();
int sum = 0;
public void accept(Integer num) {
sum +=num;
retArray.add(sum);
}
public CumulativeAdd combine(CumulativeAdd other) {
throw new UnsupportedOperationException("Parallel Stream not supported");
}
public List<Integer> finish() {
return retArray;
}
public static Collector<Integer, ?, List<Integer>> collector() {
return Collector.of(CumulativeAdd::new, CumulativeAdd::accept, CumulativeAdd::combine, CumulativeAdd::finish);
}
}

How could we split an array into two new ones which their weight differences are minimal? [duplicate]

This question already has answers here:
Minimum sum partition of an array
(3 answers)
Closed 2 years ago.
I am doing the following programming exercise: Stone pile. The statement is:
You are given pile of stones with different weights.
Your task is to divide this stone pile into two parts, so the weight
difference between the piles will be minimal. You can't break one
stone into smaller ones.
For example if we have stones:
[1, 2, 3, 4]
We could divide them into:
[2, 3], [1, 4]
So the difference will be 0
If you are given empty stone pile, you can still divide it into two
piles with no stones.
The pile will contain maximum 22 stones. 🗿
Following the examples I have thought:
Sort stones in ascending order
for each stone
if length is even
if movement is even
add min and max to right list
remove them
if movement is odd
add min and max to left list
remove them
if length is odd
if movement is even
add max to left
remove it
if movement is odd
add min to right
remove it
if there are more items
add next min
remove it
So in code would be:
import java.util.*;
import java.util.stream.*;
public class Pile {
public static int minDiff(int[] stones) {
System.out.println("stones: "+Arrays.toString(stones));
Arrays.sort(stones);
System.out.println("stones: "+Arrays.toString(stones));
List<Integer> allStones = Arrays.stream(stones).boxed().collect(Collectors.toList());
System.out.println("allStones: "+Arrays.toString(allStones.toArray()));
ArrayList<Integer> left = new ArrayList<>();
ArrayList<Integer> right = new ArrayList<>();
for(int i = 0; allStones.size()>0; i++){
if(stones.length%2==0){
if(i%2==0){
right.add(allStones.get(0));
right.add(allStones.get(allStones.size()-1));
allStones.remove(0);
allStones.remove(allStones.size()-1);
}else{
left.add(allStones.get(0));
left.add(allStones.get(allStones.size()-1));
allStones.remove(0);
allStones.remove(allStones.size()-1);
}
}else{
if(i%2==0){
left.add(allStones.get(allStones.size()-1));
allStones.remove(allStones.size()-1);
}else{
right.add(allStones.get(0));
allStones.remove(0);
if(allStones.size()>0){
right.add(allStones.get(0));
allStones.remove(0);
}
}
}
}
System.out.println("left: "+Arrays.toString(left.toArray()));
System.out.println("right: "+Arrays.toString(right.toArray()));
return left.stream().mapToInt(Integer::intValue).sum()-right.stream().mapToInt(Integer::intValue).sum();
}
}
Currently it is just working when we test it with inputs where the difference is zero. However if we test it with other inputs, it will fail.
Given the following tests, the first suite will pass, the others fail:
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.junit.runners.JUnit4;
public class PersonTest {
#Test
public void testDifferenceShouldBeZero(){
assertEquals(0, Pile.minDiff(new int[]{1, 2, 3}));
assertEquals(0, Pile.minDiff(new int[]{1, 2, 3, 4}));
assertEquals(0, Pile.minDiff(new int[]{5,5,4,3,3}));
}
#Test
public void testDifferenceShouldBeOne(){
assertEquals(1, Pile.minDiff(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}));
}
#Test
public void testDifferenceShouldBeTwo(){
assertEquals(2, Pile.minDiff(new int[]{89409, 34351, 3065, 10128, 27694, 27585, 87350, 33875, 2658, 41606, 57512, 73368, 83345, 37048, 31827, 94644, 15972, 74813, 31441, 70395}));
}
}
For example, when stones are: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
Trace is:
stones: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
stones: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
allStones: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
left: [2, 21, 4, 19, 6, 17, 8, 15, 10, 13]
right: [1, 22, 3, 20, 5, 18, 7, 16, 9, 14, 11, 12]
Being the result:
expected:<1> but was:<-23>
How could we split the stone pile in two chunks where the difference is the minimum, for the general case?
We have read:
Make copy of an array
How to convert int[] into List<Integer> in Java?
How to get the last value of an ArrayList
Is there possibility of sum of ArrayList without looping
I would use bit combination to divide the stones into two groups and sum up every possible combination, comparing them to choose the one with lowest difference:
import java.util.Arrays;
import java.util.LinkedList;
public class Pile {
/**
* return solution as int, if bit is set use the "bitNumber" as index for stone
* for one side, otherwise for the other
**/
private static int divide(int[] stones) {
int solution = -1;
long minDifference = Long.MAX_VALUE;
for (int n = 0; n < (1 << (stones.length + 1)); n++) {
long sumLeft = 0;
long sumRight = 0;
for (int bit = 0; bit < stones.length; bit++) {
boolean isSet = (n & (1 << bit)) > 0;
if (isSet) {
sumLeft += stones[bit];
} else {
sumRight += stones[bit];
}
}
long diff = Math.abs(sumLeft - sumRight);
if (diff < minDifference) {
solution = n;
minDifference = diff;
}
}
return solution;
}
public static long minDiff(int[] stones) {
int solution = divide(stones);
long sumLeft = 0;
long sumRight = 0;
LinkedList<Integer> left = new LinkedList<>();
LinkedList<Integer> right = new LinkedList<>();
for (int bit = 0; bit < stones.length; bit++) {
boolean isSet = (solution & (1 << bit)) > 0;
if (isSet) {
sumLeft += stones[bit];
left.add(stones[bit]);
} else {
sumRight += stones[bit];
right.add(stones[bit]);
}
}
System.out.println("left: " + Arrays.toString(left.toArray()));
System.out.println("right: " + Arrays.toString(right.toArray()));
return Math.abs(sumRight - sumLeft);
}
}

How to sort an array in descending order comparing the first element and the last

I'm still a student and I have an assignment in Java where I have to sort an array that compares the first element from the last element until the array is sorted out from highest to lowest. I already did some of the algorithm but it seems it jumps swap number 2 and proceeds to swap3. The program should run like this.
10, 3, 7, 15, 9
10, 3, 7, 15, 9
15, 3, 7, 10, 9 - swap1
15, 3, 7, 10, 9
15, 3, 7, 10, 9
15, 9, 7, 10, 3 - swap2
15, 10, 7, 9, 3
15, 10, 7, 9, 3
15, 10, 7, 9, 3
15, 10, 9, 7, 3 - swap3
15, 10, 9, 7, 3
So here is my algorithm doing this:
public static void main(String[] args) {
int array[] = {10,3,7,15,9};
int f;
int l;
int temp;
System.out.println("Sorting array first and last elements");
for (f = 0; f < array.length; f++)
{
for (l = 4; l > f; l--)
{
if (array[f] < array[l])
{
temp = array[l];
array[l] = array[f];
array[f] = temp;
}
}
System.out.println("sorting....");
for (int c = 0; c < array.length; c++)
System.out.print(array[c] + ",");
}
System.out.println("sorted");
}
The output is:
Sorting array first and last elements
sorting....
15,3,7,10,9,sorting....
15,10,7,9,3,sorting....
15,10,9,7,3,sorting....
15,10,9,7,3,sorting....
15,10,9,7,3,sorted
It does sort but it jumps the swap number 2 and proceeds to swap number 3. How can i do this correctly that the output shows and does not jump the swap number 2?
The outer loop goes from the first element until the end.
The inner loop goes from the last element until the index of the outer loop.
You print the content of the array after the inner loop runs.
That is, you print the content one time per iteration of the outer loop.
Keep in mind that during the inner loop,
multiple swaps can happen.
For example two swaps happen when f=1.
If you want to print the state after each swap,
then do just that, in the inner loop:
for (f = 0; f < array.length; f++) {
for (l = array.length - 1; l > f; l--) {
if (array[f] < array[l]) {
temp = array[l];
array[l] = array[f];
array[f] = temp;
System.out.println(Arrays.toString(array));
}
}
}
This will print:
[15, 3, 7, 10, 9]
[15, 9, 7, 10, 3]
[15, 10, 7, 9, 3]
[15, 10, 9, 7, 3]

Reordering the values of arrays in an int array

I want to make an array from something like this:
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
To this:
{6, 5, 4, 3, 2, 1, 0, 13, 12, 11, 10, 9, 8, 7, 20, 19, 18, 17, 16, 15, 14}
But I'm clueless how. I think this method can serve as a good alternative to the code I plan to do. (I'm using Dr. Java so no imported files BTW)
for an integer array called integer[]:
(for j = 0; j < 3; j++) {
(for k = 0; k = 6; k++) {
int newj = j+1;
int array = integer[k*newj];
integer [k*newj] = integer[6 - k*newj -1];
integer[6 - k*newj - 1] = array;
}
}
But this doesn't work.
Any advice? It's not part of an assignment, but it's part of an exam that will happen within a week and I want to be sure of this.
There are 21 elements in your array. From the description you mentioned, you want to seperate it into 3 parts. Each part has 7 elements and reverse them.
For the each part, we can do the swap data opearation.
Swap the 1st element with the 7th element.
Sawp the 2nd element with the 6th elememt.
Swap the 3rd element with the 5th element.
... ...
Note: The end condition is 7/2 for data swap. It is the middle index of the 7 elements.
Here one more thing is to determine what is the start index and end index for each divided part.
Thefollowing code is working for your requirement. Hope this can help you some.
for (int j = 0; j <3; j++) {
for (int k = 0; k <7/2; k++) {
int newj = j+1;
int array = integer[7*newj-k-1];
integer[7*newj-k-1]= integer [7*j+k];
integer [7*j+k] = array;
}
}

Trying to make a double array, numbered 2 to 50

I'm trying to make a 5 by 10 table using a double array. The first box should be blank, then the rest numbered 2-50.
I have this so far but it is not working.
int array[][] = new int[5][10];
for(int row=1; row<5;row++){
for(int col=1;col<10;col++)
array[row][col] = row*col;}
System.out.println(array);
row * col cannot give you consecutive numbers from 2 to 50. And in your code, you are not just leaving the first box, but you are leaving out first row and first column completely.
You should run the loop normally from 0 to max. And for [0][0], don't print anything.
Also, for printing from 2 to 50, just have a count variable which starts with 2, and after printing it, increment it by 1.
Here's the modified code: -
int array[][] = new int[5][10];
int count = 2;
for(int row=0; row<5;row++){
for(int col=0;col<10;col++) {
if (row == 0 && col == 0) {
continue;
}
array[row][col] = count++;
}
}
for (int[] inner: array) {
System.out.println(Arrays.toString(inner));
}
OUTPUT : -
[0, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
[31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
[41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
NOTE: -
Since you want your first box to be blank, you can't use Arrays.toString here. You would have to use one more loop, and print your array in simple ways. And when your indices are [0][0], just sysout("");
The first box can't be blank... it could be zero, is that what you want?
Changes:
Use 0 indices, not 1 indices
You have to print the contents of the array manually, see where I print a comma below
row * col isn't the correct value. use row * 10 + col + 1
Try this:
int array[][] = new int[5][10];
for(int row=0; row<5;row++){
for(int col=0;col<10;col++) {
array[row][col] = row * 10 + col + 1;
if (array[row][col] < 2) {
System.out.print(" ");
} else {
System.out.print(array[row][col]);
}
if (col < 9) System.out.print(",");
}
System.out.println();
}
Output:
,2,3,4,5,6,7,8,9,10
11,12,13,14,15,16,17,18,19,20
21,22,23,24,25,26,27,28,29,30
31,32,33,34,35,36,37,38,39,40
41,42,43,44,45,46,47,48,49,50

Categories