Can I replace my Nested if loop with something more efficient? - arrays

I try to figure out how many 1, 2, 3, 4 and 5 there is by using a for loop and if else statement. My question is: is there a more efficient way of writing it?
int A[15] = {1,5,4,1,3,1,3,4,5,2,3,2,5,3,2};
int B[5] = {};
for (int i = 0; i <= 14; i++)
{
if (A[i] == 1)
{
B[0]++;
}
else if (A[i] == 2)
{
B[1]++;
}
else if (A[i] == 3)
{
B[2]++;
}
else if (A[i] == 4)
{
B[3]++;
}
else if (A[i] == 5)
{
B[4]++;
}
}

int[] a = {1, 5, 4,...};
int[] b = new int[5];
for (int n: a) {
assert 1 <= n && n <= 5;
b[n - 1]++;
}
n will be set to every element of a.
Array elements are initialized with 0, 0.0, false, null, that is the default value of the type.
You used square brackets in a C/C++ compatible syntax. Normally the more logical notation above is used: part of the type.
Variable and function names start with a small letter by convention, and names are in camelCase.
int[] studentScores =
Asserts one rarely sees: my bad conscience for the assumption no value is out of range.

Provided that the elements of array A are greater than 0:
#include <stdio.h>
int main()
{
int A[15] = { 1, 5, 4, 1, 3, 1, 3, 4, 5, 2, 3, 2, 5, 3, 2 };
int B[5] = { 0, 0, 0, 0, 0 };
for (int i = 0 ; i < sizeof(A)/sizeof(A[0]) ; i++)
++B[A[i] - 1];
for (int i = 0 ; i < sizeof(B)/sizeof(B[0]) ; i++)
printf("%d ", B[i]);
return 0;
}
This code produces the following output:
3 3 4 2 3

Related

Check if the array is a lower triangular matrix

Write a function in c that takes a single 2d nxn matrix. If the matrix is a lower triangular matrix, the program should output 1 and output 0 if it is not a lower triangular matrix.
Here is my code.
// function code
#include <stdio.h>
#include <stdlib.h>
#define NUMS 5
int isLowerTriangularMatrix(int array[NUMS][NUMS]) {
for (int row = 0; row < NUMS; row++) {
for (int col = 0; col < NUMS; col++) {
if (row > col && array[row][col] == 0) {
return 1;
}
else {
return 0;
}
}
}
}
// test code
int main(void) {
int matrix[5][5] = {{1,2,3,4,5},
{7,8,9,2,3},
{7,8,9,2,3},
{7,8,9,2,3},
{7,8,9,2,3}};
int result = isLowerTriangularMatrix(matrix, 5);
printf("%d", result);
return 0;
}
My question is that how to modify my code?
Here is the compiler warnings
q23.c:16:1: warning: control reaches end of non-void function [-Wreturn-type]
16 | }
The warning is spurious. Or rather, it should have issued a different warning, one that indicated you have code that will never be executed.
That is to say that while your code doesn't suffer from the identified problem, it is nonetheless incorrect. It always returns zero. The first pass through the loops, you check if row > col. Since it's false, you execute the else clause and return zero.
You shouldn't be returning 0 in that case. But you shouldn't be returning 1 either. You can only return 1 after you've checked the entire matrix, so the return 1 should be outside the loops.
This fixes these problems:
int isLowerTriangularMatrix( int array[ NUMS ][ NUMS ] ) {
for ( int row = 0; row < NUMS; ++row ) {
for ( int col = 0; col < NUMS; ++col ) {
if ( col > row && array[ row ][ col ] != 0 ) {
return 0;
}
}
}
return 1;
}
There's one last issue to address, and it's the needless "visiting" of cells in the lower triangle. It's trivial to skip these.
int isLowerTriangularMatrix( int array[ NUMS ][ NUMS ] ) {
for ( int row = 0; row < NUMS; ++row ) {
for ( int col = row+1; col < NUMS; ++col ) {
if ( array[ row ][ col ] != 0 ) {
return 0;
}
}
}
return 1;
}
As I mentioned in my top comments ...
For your original question as to how to initialize a matrix:
With an initializer:
int mtx[3][3] = {
{ 3, 9, 7 },
{ 0, 5, 6 },
{ 0, 0, 1 }
};
Or, with assignment statements:
int mtx[3][3];
mtx[0][0] = 3;
mtx[0][1] = 9;
mtx[0][2] = 7;
mtx[1][0] = 0;
mtx[1][1] = 5;
mtx[1][2] = 6;
mtx[2][0] = 0;
mtx[2][1] = 0;
mtx[2][2] = 1;
#Craig Estey Yes, it is a method, but it also means the n not working very well on my code. –
Cedric xu
You do not have a true 2D int array. You have a 1D array of int * to int arrays. Do this instead:
#define NUMS 5
int mtx[NUMS][NUMS];
You can define the function as:
int isLowerTriangularMatrix(int arr[NUMS][NUMS])
Or, if you want the function to handle the size dynamically:
int isLowerTriangularMatrix(int n,int arr[n][n])
The first one will be a bit faster and the second a bit more flexible [albeit a bit slower].
Edit: Your function is being [correctly] flagged as reaching the end of the function and not having a return statement. It can't [seem to] determine that the code will always do one of the return statements inside the loops. Note that both gcc and clang flag it the same way.
I'm not sure your function will return a valid result because the if does a return on both the if and the else. So, it will never examine all the elements [that it needs to].
Usually, the inner return is just on the if part. Then, at the function bottom do: (e.g.) return 1;
Here's a refactored version:
// function code
#include <stdio.h>
#include <stdlib.h>
#define NUMS 5
int
isLowerTriangularMatrix(int array[NUMS][NUMS])
{
// we only need to probe the upper right part of the matrix
// if we see non-zero, it's _not_ triangular
for (int row = 0; row < NUMS; row++) {
for (int col = row + 1; col < NUMS; col++) {
//printf("arr[%d][%d] = %d\n",row,col,array[row][col]);
if (array[row][col] != 0)
return 0;
}
}
return 1;
}
// test code
int
main(void)
{
// this is _not_ a triangular matrix
int matrix[5][5] = {
{1, 2, 3, 4, 5},
{7, 8, 9, 2, 3},
{7, 8, 9, 2, 3},
{7, 8, 9, 2, 3},
{7, 8, 9, 2, 3}
};
int result = isLowerTriangularMatrix(matrix);
printf("%d\n", result);
// this _is_ a triangular matrix
int m2[5][5] = {
{ 1, 0, 0, 0, 0 },
{ 3, 1, 0, 0, 0 },
{ 4, 5, 1, 0, 0 },
{ 7, 6, 2, 1, 0 },
{ 8, 9, 7, 3, 1 }
};
result = isLowerTriangularMatrix(m2);
printf("%d\n", result);
return 0;
}
Here is the program output (with the debug printf):
arr[0][1] = 2
0
arr[0][1] = 0
arr[0][2] = 0
arr[0][3] = 0
arr[0][4] = 0
arr[1][2] = 0
arr[1][3] = 0
arr[1][4] = 0
arr[2][3] = 0
arr[2][4] = 0
arr[3][4] = 0
1

Checking for duplicate numbers in a 2D matrix and containing the data into two variables

I am trying to check 2D matrix array for the correct numbers and extras on each row and then printing them out only once per correct number/extra.
I.e. if 34 is twice in jackpot and once in the matrix row it should only record it once.
Correct numbers are first 7 numbers of jackpot array and the extras are the last 3 numbers.
Can anyone explain why the Row 2's 1 extra is being eliminated from my current output?
I am guessing it is because the correct number 34 is already recorded in previous[] and this is then compared to the extra 34 and thus extra is substracted by 1.
How would one go about fixing this, should I make another array that stores the previous extras or something?
The correct output:
Row 1 has 0 correct and 0 extras!
Row 2. has 1 correct and 1 extras!
Row 3. has 3 correct and 0 extras!
Row 4. had 1 correct and 1 extras!
Row 5. has 1 correct and 0 extras!
My current output:
Row 1. has 0 correct and 0 extras!
Row 2. has 1 correct and 0 extras!
Row 3. has 3 correct and 0 extras!
Row 4. has 1 correct and 1 extras!
Row 5. has 1 correct and 0 extras!
for (int z = 0; z < NUM_PER_ROW; z++)
{
if (previous[z] == jackpot[k] && k <= 6)
{
correct -=1;
break;
}
else if (previous[z] == jackpot[k] && k > 6)
{
extra -=1;
break;
}
}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_ROWS 5
#define NUM_PER_ROW 7
#define MAX_NUM 40
int doStuff();
int doStuff()
{
int matrix[MAX_ROWS][NUM_PER_ROW] = {
{ 1, 2, 3, 4, 5, 6, 7},
{30, 38, 6, 34, 4, 39, 30},
{ 9, 37, 32, 27, 9, 39, 17},
{ 8, 26, 6, 31, 28, 29, 16},
{33, 21, 19, 7, 9, 19, 30} };
int jackpot[NUM_PER_ROW + 3] =
{20, 37, 22, 9, 34, 28, 34, 24, 26, 29};
int num = 0, i, j, cnt = 0, temp = 0;
for(i = 0; i < MAX_ROWS; i++)
{
int correct = 0;
int extra = 0;
for(j = 0; j < NUM_PER_ROW; j++)
{
int previous[7] = {0, 0, 0, 0, 0, 0, 0};
for (int k = 0; k < NUM_PER_ROW + 3; k++)
{
if (matrix[i][j] == jackpot[k])
{
for (int z = 0; z < NUM_PER_ROW; z++)
{
if (previous[z] == jackpot[k] && k <= 6)
{
correct -= 1;
break;
}
else if (previous[z] == jackpot[k] && k > 6)
{
extra -=1;
break;
}
}
if (k <= 6)
{
correct += 1;
}
else
{
extra += 1;
}
previous[j] = jackpot[k];
}
}
}
printf("Row %d. has %d correct and %d extras! \n", i + 1, correct, extra);
}
return 0;
}
int main()
{
int num;
srand(time(NULL));
doStuff(num);
return 0;
}
Thank you for your time!
I suggest using an array to mark the duplicates in jackpot[]:
char jp_dupe[NUM_PER_ROW + 3];
for (i = 0; i < NUM_PER_ROW + 3; i++)
{
for (j = 0; j < i && jackpot[i] != jackpot[j]; j++)
;
jp_dupe[i] = (i != j); /* 0 if first occurrence, 1 if a duplicate */
}
Then there is no need for the previous[] array or the z loop, and the k loop can be simplified:
for (int k = 0; k < NUM_PER_ROW + 3; k++)
{
if (!jp_dupe[k] && matrix[i][j] == jackpot[k])
{
if (k < NUM_PER_ROW)
{
correct += 1;
}
else
{
extra += 1;
}
}
}
I took the liberty of replacing the <= 6 test to avoid the magic number. The magic number 3 could also be replaced with a macro.

How to check if two arrays have the same set of digits in C?

I want to check if two integer type arrays have the same set of digits. For example, if array 1 is 5 1 2 3 3 4 6 1, and array 2 is 1 2 3 4 5 6, the program returns 1. If any number from either array isn't in the second one, the program returns a 0.
I tried doing something like this, but I can't get it to work:
#include <stdio.h>
int main()
{
int i, j, a[8]={5, 1, 2, 3, 3, 4, 6, 1}, b[6]={1, 2, 3, 4, 5, 6}, x=0;
for(i=0; i<6; i++)
{
for(j=0; j<8; j++)
{
if(a[j]==b[i])
{
x=1;
continue;
}
else
{
x=0;
break;
}
}
}
return x;
}
EDIT:
Thank you Some programmer dude
#include <stdio.h>
void sort(int arr[], int n)
{
int i, j, a;
for (i=0; i<n; i++)
{
for (j=i+1; j<n; j++)
{
if (arr[i]>arr[j])
{
a=arr[i];
arr[i]=arr[j];
arr[j]=a;
}
}
}
}
int main()
{
int i, j, k;
int a[8]={5, 1, 2, 3, 3, 4, 6, 1};
int b[6]={1, 2, 3, 4, 5, 6};
int na=8, nb=6;
for(i=0; i<na; i++) // removing duplicates from a
{
for(j=i+1; j<na; j++)
{
if(a[i]==a[j])
{
for(k=j; k<na; k++)
{
a[k]=a[k+1];
}
na--;
j--;
}
}
}
for(i=0; i<nb; i++) // removing duplicates from b
{
for(j=i+1; j<nb; j++)
{
if(b[i]==b[j])
{
for(k=j; k<nb; k++)
{
b[k]=b[k+1];
}
nb--;
j--;
}
}
}
sort(a, na);
sort(b, nb);
if(na!=nb)
return 0;
for(i=0; i<na; i++)
{
if(a[i]!=b[i])
return 0;
}
return 1;
}
You have several ways you can approach this, you can use two sets of nested loops swapping the order you loop over the two arrays validating each element is found in the other. Two full sets of nested loops are needed as you have a 50/50 chance any single outlier will be contained in either of the arrays. This is the brute-force method and has the potential worst-case number of iterations.
Since an outlier is what drove the need for looping with one arrays as outer and the other inner and then swapping a repeating, e.g. to catch 5, 1, 2, 3, 3, 4, 6, 1 and 1, 2, 3, 4, 5, 6, 7, if you can catch the outlier with another method that requires fewer iterations you can make your algorithm more efficient.
An outlier would be detected in a comparison of the min and max from each array, and to find min and max only requires a single linear traversal of each array. Much better than the worst-case nested loop over all elements.
The min and max check provide a way to shorten your work, but do not eliminate the need to press forward with a second set of nested loops if the result is inconclusive at that point. Why? Consider the following sets, where the min and max are equal, but one element within the range is not included in both arrays, e.g.:
int a[] = { 5, 1, 2, 3, 3, 4, 6, 112 },
b[] = { 1, 2, 3, 4, 5, 6, 7, 112 };
The only way the 7 will be detected is by nested loop with the array containing 7 being the outer loop.
So you could write a short function to test for the common set as:
#include <stdio.h>
#include <limits.h>
int commonset (int *a, int *b, int sza, int szb)
{
int maxa = INT_MIN, maxb = INT_MIN,
mina = INT_MAX, minb = INT_MAX;
for (int i = 0; i < sza; i++) { /* find max/min of elements of a */
if (a[i] > maxa)
maxa = a[i];
if (a[i] < mina)
mina = a[i];
}
for (int i = 0; i < szb; i++) { /* find max/min of elements of b */
if (b[i] > maxb)
maxb = b[i];
if (b[i] < minb)
minb = b[i];
}
if (maxa != maxb || mina != minb) /* validate max & mins equal or return 0 */
return 0;
for (int i = 0; i < sza; i++) { /* compare of each element between arrays */
int found = 0;
for (int j = 0; j < szb; j++)
if (a[i] == b[j]) {
found = 1;
break;
}
if (!found)
return 0;
}
for (int i = 0; i < szb; i++) { /* compare of each element between arrays */
int found = 0;
for (int j = 0; j < sza; j++)
if (a[j] == b[i]) {
found = 1;
break;
}
if (!found)
return 0;
}
return 1;
}
Adding a short example program:
int main (void) {
int a[] = { 5, 1, 2, 3, 3, 4, 6, 1 },
sza = sizeof a / sizeof *a,
b[] = { 1, 2, 3, 4, 5, 6 },
szb = sizeof b / sizeof *b,
result;
result = commonset (a, b, sza, szb);
if (result)
puts ("arrays have common set of numbers");
else
puts ("arrays have no common set of numbers");
return result;
}
Example Use/Output
$ ./bin/arr_commonset
arrays have common set of numbers
$ echo $?
1
With b[] = { 1, 2, 3, 4, 5, 6, 7 }:
$ ./bin/arr_commonset
arrays have no common set of numbers
$ echo $?
0
With a[] = { 5, 1, 2, 3, 3, 4, 6, 112 } and b[] = { 1, 2, 3, 4, 5, 6, 7, 112 }:
$ ./bin/arr_commonset
arrays have no common set of numbers
$ echo $?
0
There are probably even ways to combine the two and shave off a few iterations, and, if you have a guaranteed range for your input sets, you can use a simple frequency array for each and then two simple linear iterations would be needed to increment the element that corresponds to the index for each value in the array, and then a third linear iteration over both frequency arrays comparing that like indexes either both are non-zero or both are zero to confirm the common set -- that is left to you.
Look things over and let me know if you have any further questions.

Why it is this program not finding pairs in an array that sum to a given value?

My code so far:
#include<stdio.h>
int main() {
int a[5][5] = {
{-1, 2, 3, 4 },
{ 5, 3, -2, 1 },
{ 6, 7, 2, -3 },
{ 2, 9, 1, 4 },
{ 2, 1, -2, 0 }
};
int sum = 11;
int i, j;
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
if (a[i][j] + a[j][i] == sum && i != j) {
printf("%d %d\n", i, j);
}
}
}
}
I want to find pairs with given sum such that elements of pair are in different rows.
Note that a is a 5x5 array with an extra column of zeros. That has a benign effect.
Your algorithm is faulty! If you adjust your conditional to
if (a[i][j] + a[j][i] == sum && i != j) {
printf("Yes %d %d\n", i, j);
} else {
printf("No %d %d\n", i, j);
}
it becomes obvious that you are not considering the sum of every possible pair. The ones that get missed out are, by coincidence, the pairs that sum to 11.
Essentially you need 4 nested loops, and you need to consider every number with every other number in the array.
First, you should notice that you defined a 5X5 int array but only filled in 4 ints in each sub-array. If you would print out your array, you'll see the values are:
-1 2 3 4 0
5 3 -2 1 0
6 7 2 -3 0
2 9 1 4 0
2 1 -2 0 0
I guess that wasn't your intention...
Now, for your question - you want to find a[i][j] + a[j][i] == 11 for i!=j. The reason you get no output is because there aren't such elements that satisfy your conditions in the array you defined.
Below program will solve your problem,
#include<stdio.h>
int main()
{
int a[5][5] = {
{-1, 2, 3, 4 },
{ 5, 3, -2, 1 },
{ 6, 7, 2, -3 },
{ 2, 9, 1, 4 },
{ 2, 1, -2, 0 }
};
int sum=11,i,j,k,l;
for(i=0;i<5;i++)
{
for(j=i+1;j<5;j++)
{
for(k=0;k<5;k++)
{
for(l=0;l<5;l++)
{
if(a[i][k]+a[j][l]==sum)
printf("a[%d][%d] = %d\ta[%d][%d] = %d\n",i,k,a[i][k],j,l,a[j][l]);
}
}
}
}
}
if you want "pairs with given sum such that elements of pair are in different rows." then you should try code like this:
#include<stdio.h>
int main()
{
const int rows = 5;
const int cols = 4;
int sum = 11;
int i, j, i1, j1;
int a[rows][cols] =
{
{-1, 2, 3, 4 },
{ 5, 3, -2, 1 },
{ 6, 7, 2, -3 },
{ 2, 9, 1, 4 },
{ 2, 1, -2, 0 }
};
for(i = 0; i < rows; i++)
for(j = 0; j < cols; j++)
for(i1 = i + 1; i1 < rows; i1++)
for(j1 = 0; j1 < cols; j1++)
if(a[i][j] + a[i1][j1] == sum)
printf("[%d %d](%d); [%d %d](%d)\n", i, j, a[i][j], i1, j1, a[i1][j1]);
}

How to split/divide array using user input

#include <stdio.h>
int main( )
{
int length = 0;
int divide = 0;
int count = 0;
int i;
printf("Set the length of array: \n");
scanf("%d", &length);
int array[length];
for(i = 0; i < length; i++)
{
scanf("%d", &array[i]);
}
printf("Divide array into subarray: \n");
scanf("%d", &divide);
for(i = 0; i < divide; i++)
{
int countfrom = length / divide * i;
int countto = countfrom + length / divide;
for(int j = countfrom; j < countto; j++)
{
if( array[j] == 1 && array[j+1] == 0 && array[j+2] == 1)
{
count++;
}
}
}
printf("count: %d\n", count);
return 0;
}
This is what I have so far. The purpose is to define the length of array from user input and divide it into subarray (int divide is also from the user input).
The main purpose is to count the number of times the sequence, 101 is found in the divided subarray. It works well, except for the value that is odd. For example, array[length(value: 17)] = {1, 0, 1, 2, 7, 9, 6, 5, 0, 1, 0, 1, 0, 1, 1, 0}, and if the divide value is 5, then the subarrays should be,
{1, 0, 1}, {2, 7, 9}, {6, 5, 0}, {0, 1, 0}, {1, 0, 1}, {1, 0}, and the value for the count should be 3. However, it prints out four.
I initially was misinterpreting "101 is found in the divided subarray" as meaning the subarray would have to actually be 101. the j loop is indeed needed if you want to search the subarray, but you do need a bounds check.
if( array[j] == 1 && array[j+1] == 0 && array[j+2] == 1)
should be
if( j+2 < countto && array[j] == 1 && array[j+1] == 0 && array[j+2] == 1)
(or you can initially decrement countto by 2 and adjust it tto at most length-2).
Original answer:
From your description, it doesn't look like you need the j loop or countto at all; in the i loop, you should just be checking array[countfrom]==1 && array[countfrom+1]==0 && array[countfrom+2]==1 (and also first checking that countfrom + 2 < length so you don't go past the end of your array).
But then your code is assuming you have "subarrays" of length 3; you should check that that is actually true given the input, and give an error message if it is not.

Resources