Related
I have 2 variables A and B
if A =1 then B should B=2
and if A=2 then B should B=1
Like this, there are 3 pairs 1-2,3-4,5-6
What's the best way of making a code instead of just if-else
It is possible to use simple addition and subtraction to get the other element of the two (x, x + 1):
int a = 1; // the other is 2, sum is 3
int b = 3 - a; // if a = 2, b = 1
int c = 3; // the other is 4, sum is 7
int d = 7 - c; // if c = 4, d = 3
int m = 5; // the other is 6, sum is 11
int n = 11 - m;
Another approach could be using the following logic:
if (a % 2 == 1) b = a + 1;
else b = a - 1;
So, an array could be used to provide +/- 1:
static int[] signs = {-1, 1};
public static int nextWithArrPositive(int a) {
return a + signs [a % 2];
}
This expression fails to work for negative a as in this case a % 2 == -1 and more advanced logic would be required to calculate the value properly to take into account the negative remainder:
public static int nextWithArr(int a) {
int sign = (a & 0x80000000) >> 31; //-1 if a < 0, 0 otherwise
// a >= 0 : 0 - even, 1 - odd;
// a < 0 : 1 - even, 0 - odd
return a + signs[a % 2 - sign];
}
However, a simpler expression can be designed:
public static int nextWithMod(int a) {
return a + a % 2 - (a - 1) % 2;
}
Let's compare the results of the three implementations including xor solution b = ((a - 1) ^ 1) + 1 offered in the comments by user3386109:
public static int nextXor(int a) {
return ((a - 1) ^ 1) + 1;
}
Tests:
System.out.println("+-----+-----+-----+-----+");
System.out.println("| a | arr | mod | xor |");
System.out.println("+-----+-----+-----+-----+");
for (int i = -6; i < 7; i++) {
System.out.printf("| %2d | %2d | %2d | %2d |%n", i, nextWithArr(i), nextWithMod(i), nextXor(i));
}
System.out.println("+-----+-----+-----+-----+");
Output:
+-----+-----+-----+-----+
| a | arr | mod | xor |
+-----+-----+-----+-----+
| -6 | -5 | -5 | -7 |
| -5 | -6 | -6 | -4 |
| -4 | -3 | -3 | -5 |
| -3 | -4 | -4 | -2 |
| -2 | -1 | -1 | -3 |
| -1 | -2 | -2 | 0 |
| 0 | -1 | 1 | -1 |
| 1 | 2 | 2 | 2 |
| 2 | 1 | 1 | 1 |
| 3 | 4 | 4 | 4 |
| 4 | 3 | 3 | 3 |
| 5 | 6 | 6 | 6 |
| 6 | 5 | 5 | 5 |
+-----+-----+-----+-----+
One simple solution is a table lookup. In an array for each possible value of a I store the corresponding value of b:
private static final int[] B_PER_A = { -1, 2, 1, 4, 3, 6, 5 };
Since array indices always start at 0 in Java, we need to put a dummy value at index 0. This value is never used (or should never be, at least).
Let’s try it out:
for (int a = 1; a <= 6; a++) {
int b = B_PER_A[a];
System.out.format("a: %d; b: %d.%n", a, b);
}
Output:
a: 1; b: 2.
a: 2; b: 1.
a: 3; b: 4.
a: 4; b: 3.
a: 5; b: 6.
a: 6; b: 5.
Generalized to more than 3 pairs
If you need to handle a variable number of pairs, resort to math.
public static int calcB(int a) {
// 0-based index of pair (0 = 1-2, 1 = 3-4, etc.)
int pairNumber = (a - 1) / 2;
// a + b for given pair
int pairSum = 4 * pairNumber + 3;
int b = pairSum - a;
return b;
}
In each pair the sum is equivalent to 3 modulo 4. I am exploiting this fact in finding the sum for a given pair. When I subtract a from that sum, I get b. Let’s see that demonstrated too:
for (int a = 1; a <= 8; a++) {
int b = calcB(a);
System.out.format("a: %d; b: %d.%n", a, b);
}
a: 1; b: 2.
a: 2; b: 1.
a: 3; b: 4.
a: 4; b: 3.
a: 5; b: 6.
a: 6; b: 5.
a: 7; b: 8.
a: 8; b: 7.
The latter solution is more complicated and harder to read. So if you always have got three pairs, no more, no less, I recommend the simpler table lookup presented first.
I'm trying to do a Lotto game where I have to generate a random card and in the first column numbers go from 1-9, second 10-19 all the way to 90. Another rule of the card is that it can only have 5 numbers at random positions in each line and that's what I'm having trouble with.
I've started with this to put numbers in each column:
int[][] numberCard = new int[3][9];
for (int i = 0; i < numberCard.length; i++) {
numberCard[i][0] = randInt(1, 9);
}
for (int j = 0; j < numberCard.length; j++) {
numberCard[j][1] = randInt(10, 19);
}
And then do put 5 numbers in a number position in each line of the array i tried this:
//Five numbers first line
Random random0 = new Random();
int randomLocation = 0;
while (randomLocation < 5) {
int z0 = random0.nextInt(numberCard.length);
int b0 = random0.nextInt(numberCard[0].length);
if (numberCard[z0][b0] > 0) {
numberCard[z0][b0] = 0;
randomLocation++;
}
}
//Five numbers second line
Random random1 = new Random();
int randomLocation1 = 0;
while (randomLocation1 < 5) {
int z1 = random1.nextInt(numberCard.length);
int b1 = random1.nextInt(numberCard[1].length);
if (numberCard[z1][b1] > 0) {
numberCard[z1][b1] = 0;
randomLocation1++;
}
}
And then the same for the third one.
Output:
0 | 18 | 0 | 0 | 46 | 0 | 61 | 72 | 88 |
0 | 18 | 0 | 31 | 0 | 55 | 0 | 0 | 0 |
0 | 0 | 23 | 34 | 45 | 0 | 0 | 0 | 80 |
The problem is that sometimes I get 5 numbers, sometimes 6 and sometimes 4 when sometimes i get the perfect 5 numbers in each line. More frustrating that not working is only working sometimes...
I thought and I think it is because of the random numbers that sometimes repeat themselves so they go to the same index, but then sometimes I have more than the 5 numbers so that makes no sense.
Correct output expected:
0 | 18 | 23 | 30 | 48 | 0 | 0 | 76 | 0 |
0 | 12 | 24 | 0 | 0 | 58 | 61 | 78 | 0 |
1 | 17 | 0 | 0 | 42 | 54 | 0 | 0 | 86 |
Here is the pretty much the same code as before. The cards have become the rows.
public static void lottery() {
System.out.println(" 1 2 3 4 5 6 7 8 9");
System.out.println("---------------------------");
for (int card = 1; card<= 5; card++) {
List<Integer> numbers = new ArrayList<>();
for (int i = 0; i <= 8; i++) {
int s = i > 0 ? 0 : 1;
numbers.add(ThreadLocalRandom.current().nextInt(i*10 + s,(i+1)*10));
}
Collections.shuffle(numbers);
int[] row = new int[9];
for (int s = 0; s < 5; s++) {
int pick = numbers.get(s);
row[pick/10] = pick;
}
for (int i = 0; i < 9; i++) {
System.out.printf("%3d", row[i]);
}
System.out.println();
}
}
Prints
1 2 3 4 5 6 7 8 9
---------------------------
5 0 0 0 47 0 67 71 81
1 0 22 0 0 55 65 0 88
1 11 0 30 0 58 0 76 0
0 10 24 0 43 0 0 75 88
3 16 0 0 0 0 60 71 81
I think your approach is complicated than it should be. I would recomend to do it like below:
For each row of your 2D-Array, generate a random number between [1 - 90) and put it to the spot where it belongs by dividing the random number with 10 (will give you values [0 - 8]) while checking that that position doesn't have a random value aready assigned. Reapet this 5 times.
public static void main(String[] args) {
int[][] numberCard = new int[3][9];
Random rand = new Random();
for (int i = 0; i < numberCard.length; i++) {
for (int j = 0; j < 5; j++) {
int x = rand.nextInt(89) + 1;
while (numberCard[i][x / 10] != 0) {
x = rand.nextInt(89) + 1;
}
numberCard[i][x / 10] = x;
}
}
//print or do whatever with your numberCard array
for (int[] row : numberCard) {
System.out.println(Arrays.toString(row));
}
}
Sample output:
[0, 0, 24, 0, 40, 55, 0, 71, 86]
[0, 16, 0, 0, 42, 56, 0, 70, 84]
[5, 12, 0, 0, 49, 0, 69, 0, 82]
You can do it like this:
The card consists of 3 rows.
Each row consists of 9 random cells: 5 filled and 4 hollow.
Column ranges: 1-9 first, 80-90 last, x0-x9 others.
No duplicate numbers in every column.
List<int[]> card = new ArrayList<>();
IntStream.range(0, 3)
// prepare a list of cell indices of the row
.mapToObj(row -> IntStream.range(0, 9)
.boxed().collect(Collectors.toList()))
// random order of cell indices
.peek(Collections::shuffle)
// list of 5 random cell indices in the row
.map(list -> list.subList(0, 5))
// fill the cells with random numbers
.map(list -> IntStream.range(0, 9)
// if this cell is in the list, then fill
// it with a random number, otherwise 0
.map(i -> {
int number = 0;
if (list.contains(i)) {
// unique numbers in each column
boolean isPresent;
do {
// [1-9] first, [80-90] last, [x0-x9] others
number = (int) ((i > 0 ? i * 10 : 1)
+ Math.random()
* (i < 8 ? (i > 0 ? 10 : 9) : 11));
isPresent = false;
for (int[] row : card)
if (row[i] == number)
isPresent = true;
} while (isPresent);
}
return number;
}).toArray())
// add this row to the card
.forEach(card::add);
// output
card.stream()
// row of numbers to string
.map(row -> Arrays.stream(row)
.mapToObj(j -> j == 0 ? " " : String.format("%2d", j))
// concatenate cells into one row
.collect(Collectors.joining(" | ", "| ", " |")))
.forEach(System.out::println);
Output:
| 7 | 20 | | | 47 | 53 | | | 86 |
| | | 27 | 38 | | | 63 | 80 | 85 |
| 4 | | 26 | | | | 69 | 77 | 81 |
I'm currently learning Java online and am confused about the following code and what one of the elements in the array is evaluating to:
int[] a = new int[]{9, 8, 3, 1, 5, 4};
for (int i = 0; i < a.length; i++) {
if (a[i] % 2 == 0) {
a[i] += 1;
} else if (a[i] < a.length) {
a[i] += a[a[i]];
}
}
I am looking at a[3] and the number that this evaluates to, and when I am debugging the code, my IDE is showing that a[a[i]] is evaluating to 9, which is where I'm a bit confused.
I thought that a[3] would equal 1 and then a[1] would equal 8, however this doesn't seem to be the case. Could anyone provide clarity as the JetBrains Academy course doesn't refer to this.
Note the first condition - if (a[i] % 2 == 0) {a[i] += 1;} - this causes even values to be incremented. Therefore a[1] is incremented from 8 to 9.
Now, when i==3, a[a[i]] is evaluated to a[1] which is equal to 9. Then you are adding it to the original value of a[3] (note the operator is +=, not =), so a[3] becomes 1 + 9, which is 10.
int[] a = new int[] {9, 8, 3, 1, 5, 4};
for (int i = 0; i < a.length; i++){
if (a[i] % 2 == 0)
a[i] += 1;
else if(a[i] < a.length)
a[i] += a[a[i]];
}
|i | a[i] old | a[i] % 2 | a[i] < a.length | a[a[i]] | a[i] new |
|--|----------|----------|-----------------|---------|----------|
|0 | 9 | - | - | NaN | 9 |
|1 | 8 | + | - | NaN | 9 |
|2 | 3 | - | + | 1 | 4 |
|3 | 1 | - | + | 9 | 10 |
|4 | 5 | - | + | 4 | 9 |
|5 | 4 | + | - | 9 | 5 |
// a = {9, 9, 4, 10, 9, 5};
I thought that a[3] would equal 1
That's correct, at step 3, a[3] = 1
and then a[1] would equal 8
That's not correct, because at step 1 it was incremented to 9
Its okey.
Best way to see what you are doing is debuggin(painting in this case)
your code:
int[] a = new int[] {9, 8, 3, 1, 5, 4};
for (int i = 0; i < a.length; i++){
if (a[i] % 2 == 0){
System.out.printf(a[i]);
a[i] += 1;
System.out.printf(a[i]);
}else if(a[i] < a.length){
System.out.printf(a[i]);
a[i] += a[a[i]];
System.out.printf(a[i]);
}
And you will see more clearly.Sometimes its better to face the wall by ourselves because one best practices is learn about you. Good luck!.
I'm triying to do a matrix multiplication with divide and conquer. So, I think, I already have the descompose part into subproblems (the recursive case and the base case).
Thus, I have four quadrants (left superior, left inferior, right superior, right inferior) and I'm thinking about how to combine those into a result matrix, and I don't have an idea.
I'm working with Java, so I have matrixA and matrixB, and I have some indexes like, matrixRowsA, matrixColumnsA, matrixRowsB, matrixColumnsB
By this way I'm avoiding to create new matrix and all that stuff that only makes more expensive the problem resolution.
So the basic question is, how to join 4 submatrix into a fill one?
So the method is call divideAndConquer:
private static int[][] divideAndConquer(int[][]matrixA, int beginRowsA, int endRowsA, int beginColumnsA,
int endColumnsA, int[][]matrixB, int beginRowsB, int endRowsB,
int beginColumnsB, int endColumnsB)
{
// Base case
if(lengthOfBothMatrix()==1)
{
return multiplyMatrix(matrixA,matrixB);
}
}
else
{
int middleRowsA = obtainMiddleRowsB();
int middleColumnsA = obtainMiddleColumnsA();
int middleRowsB = obtainMiddleRowsB();
int middleColumnsB = obtainMiddleColumnsB();
int[][] leftSuperiorQuadrant = matrixAddition(divideAndConquer(matrixA, beginRowsA, middleRowsA, beginColumnsA, middleColumnsA, matrixB, beginRowsB,
middleRowsB, beginColumnsB, middleColumnsB),
divideAndConquer(matrixA, beginRowsA, middleRowsA, middleColumnsA+1, endColumnsA,
matrixB, middleRowsB+1, endRowsB, beginColumnsB, middleColumnsB));
int[][] leftInferiorQuadrant = matrixAddition(divideAndConquer(matrixA, middleRowsA+1, endRowsA, beginColumnsA, middleColumnsA,
matrixB, beginRowsB,middleRowsB, beginColumnsB, middleColumnsB),
divideAndConquer(matrixA, middleRowsA+1, endRowsA, middleColumnsA+1, endColumnsA,
matrixB, middleRowsB+1, endRowsB, beginColumnsB, middleColumnsB));
int[][] rightSuperiorQuadrant = matrixAddition(divideAndConquer(matrixA, beginRowsA, middleRowsA, beginColumnsA, middleColumnsA,
matrixB, beginRowsB, middleRowsB, middleColumnsB+1, endColumnsB),
divideAndConquer(matrixA, beginRowsA, middleRowsA, middleColumnsA+1, endColumnsA,
matrixB, middleRowsB+1, endRowsB, middleColumnsB+1, endColumnsB));
int[][] rightInferiorQuadrant =matrixAddition(divideAndConquer(matrixA, middleRowsA+1, endRowsA, beginColumnsA, middleColumnsA,
matrixB, beginRowsB, middleRowsB, middleColumnsB+1, endColumnsB),
divideAndConquer(matrixA, middleRowsA+1, endRowsA, middleColumnsA+1, endColumnsA,
matrixB, middleRowsB+1, endRowsB, middleColumnsB+1, endColumnsB));
I'm testing with two matrix like:
1 | 2 | 3 | 4 |
1 | 2 | 3 | 4 |
1 | 2 | 3 | 4 |
1 | 2 | 3 | 4 |
1 | 2 | 3 | 4 |
1 | 2 | 3 | 4 |
1 | 2 | 3 | 4 |
1 | 2 | 3 | 4 |
First, you can concat vertically the left matrices (leftSuperiorQuadrant & leftInferiorQuadrant) and right matrices (rightSuperiorQuadrant & rightInferiorQuadrant) into a new columns matrices with System.arraycopy():
int leftSuperiorQuadrant [][] = {{1, 2}, {3, 4}};
int rightSuperiorQuadrant [][] = {{5, 6}, {7, 8}};
int leftInferiorQuadrant [][] = {{9, 10}, {11, 12}};
int rightInferiorQuadrant [][] = {{13, 14}, {15, 16}};
int m_intermediate_left[][] = new int[leftSuperiorQuadrant.length+leftInferiorQuadrant.length][];
int m_intermediate_right[][] = new int[rightSuperiorQuadrant.length+rightInferiorQuadrant.length][];
// Concat leftSuperiorQuadrant and leftInferiorQuadrant in column
System.arraycopy(leftSuperiorQuadrant, 0, m_intermediate_left, 0, leftSuperiorQuadrant.length);
System.arraycopy(leftInferiorQuadrant, 0, m_intermediate_left, leftSuperiorQuadrant.length, leftInferiorQuadrant.length);
// Concat rightSuperiorQuadrant and rightInferiorQuadrant in column
System.arraycopy(rightSuperiorQuadrant, 0, m_intermediate_right, 0, rightSuperiorQuadrant.length);
System.arraycopy(rightInferiorQuadrant, 0, m_intermediate_right, rightSuperiorQuadrant.length, rightInferiorQuadrant.length);
System.out.println(Arrays.deepToString(m_intermediate_left));
System.out.println(Arrays.deepToString(m_intermediate_right));
This returns:
[[1, 2], [3, 4], [9, 10], [11, 12]]
1 | 2
3 | 4
9 | 10
11 | 12
[[5, 6], [7, 8], [13, 14], [15, 16]]
5 | 6
7 | 8
13 | 14
15 | 16
Then, you can concat these resulting matrices horizontally manually:
int m_final[][] = new int[m_intermediate_left.length][m_intermediate_left[0].length+m_intermediate_right[0].length];
// For each row of the final matrix
for(int i = 0; i < m_final.length; i++) {
// For each column of the final matrix
for (int j = 0; j < m_final[0].length; j++) {
// If j corresponds to the left columns, add left matrix values
if (j < m_intermediate_left[0].length) {
m_final[i][j] = m_intermediate_left[i][j];
}
// If j corresponds to the right columns, add the right matrix values
else {
m_final[i][j] = m_intermediate_right[i][j - m_intermediate_left[0].length];
}
}
}
System.out.println(Arrays.deepToString(m_final));
This returns your desire matrix:
[[1, 2, 5, 6], [3, 4, 7, 8], [9, 10, 13, 14], [11, 12, 15, 16]]
1 | 2 | 5 | 6
3 | 4 | 7 | 8
9 | 10 | 13 | 14
11 | 12 | 15 | 16
Note that it won't work if your quadrants have different sizes.
Best
I still wanted:
to point out, that the division in divide and conquer should be along the (multiplication's) algorithm's "break" lines;
to mention the nice Arrays class.
Doing a sensible division, the laziest effort, is important.
For matrix multiplication, a split in half seems more appropriate:
Very sketchy:
A: (3x5) B: (5x3) A x B: (3x3)
a a b b b c c c ... ac ... bd ...
a a b b b c c c
a a b b b d d d
d d d
d d d
As you see, you can split the task in Aa x Bc and Ab x Bd, and then cleanly combine the results.
This is sufficiently complex, and is also easy to understand.
An other tip would be to use more mathematical short names for ease of reading. Though ordinarily one should use adequately long names, and the course may require the contrary.
int[][] multiply(int[][] a, int[][] b) {
int rows = a.length;
int cols = b[0].length;
int terms = b.length:
if (terms != a[0].length) {
throw new IllegalArgumentException(
"Dimensions do not match: " + a[0].length + " != " + terms);
}
int[][] product = new int[rows][cols];
if (terms < 2) { // Cannot divide
if (terms == 1) {
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
product[i][j] = a[i][0] * b[0][j];
}
}
}
} else {
int half = terms/2;
int[][] aLeft = new int[rows][half];
int[][] bTop = new int[half][cols];
... fill using Arrays.copyOfRange ...
int[][] prodLT = multiply(aLeft, bTop);
int[][] aRight = new int[rows][terms - half];
int[][] bBottom = new int[terms - half][cols];
... fill using Arrays.copyOfRange ...
int[][] prodRB = multiply(aRight, bBottom);
... add prodLT to prodRB into product
}
return product;
}
The task is to concat the binary of 2 given numbers.
Example:
Given 5 (101) and 3 (011), the result is 46 (concat(101, 011) = 101011)
The code thus far:
public class Concat {
public static void main(String[] args) {
int t = 0;
int k = 5;
int x = 3;
int i = 0;
while (i < 3) {
t = x % 2;
x /= 2;
k <<= 1;
k |= t;
++i;
}
System.out.println(k);
}
}
But the problem is that the above code gives 101110, not 101011.
What's the problem?
Your problem is that you're feeding the bits of the second number in backwards. That's because x%2 is the low order bit:
+---+---+---+ <110
| 1 | 0 | 1 | <-----------------+^
+---+---+---+ |1
+---+---+---+ |1
| 0 | 1 | 1 | ----+0
+---+---+---+ 011>
Cringe at my awesome artistic abilities :-) However, if you already know that it's 3 bits wide, just use:
public class concat {
public static void main (String[] args) {
int t = 0;
int k = 5;
int x = 3;
k <<= 3;
k |= x;
// or, in one line: k = (k << 3) | x;
System.out.println(k);
}
}
In terms of how that looks graphically:
+---+---+---+
k:| 1 | 0 | 1 |
+---+---+---+
+---+---+---+
x:| 0 | 1 | 1 |
+---+---+---+
+---+---+---+---+---+---+
k<<=3:| 1 | 0 | 1 | 0 | 0 | 0 |
+---+---+---+---+---+---+
+---+---+---+
x:| 0 | 1 | 1 |
+---+---+---+
+---+---+---+---+---+---+
k|=3:| 1 | 0 | 1 | 0 | 1 | 1 |
+---+---+---+---+---+---+
^ ^ ^
+---+---+---+
x:| 0 | 1 | 1 |
+---+---+---+
There's no apparent reason for doing it one bit at a time.
You just shift one number and then or with the other number:
int a = 5;
int b = 3;
int c = (a << 3) | b;
I don't know what language you are using, it's almost Java, so I am going with that.
This returns the result you are asking for, though you haven't given rules for determining how you know that 3 should be 011 instead of 11.
I have made the assumption that you want to assume that both numbers have the same number of bits, so 3 is 011 because 5 requires 3 bits.
public class Concat {
public static void main(String[] args) {
System.out.println( joinNums(3,5) );
}
public static int numBits( int n ) {
return (int)Math.ceil( Math.log(n) / Math.log(2) );
}
public static int joinNums( int num1 , int num2 ) {
int bits = Math.max( numBits(num1) , numBits(num2) );
return (num1 << bits) + num2;
}
}