Best alternative to using a long series of if if else statements in C?

I originally used switch / case, but the condition was to be a constant value that would match the variable, compared to the boolean of whether the variable was within the range.

Instead, I have this monster:

if ( data[y] > 91 ) { grades[9] = grades[9] + 1; } else if ( data[y] > 88 && data[y] < 92 ) { grades[8] = grades[8] + 1; } else if ( data[y] > 84 && data[y] < 89 ) { grades[7] = grades[7] + 1; } else if ( data[y] > 81 && data[y] < 85) { grades[6] = grades[6] + 1; } else if ( data[y] > 79 && data[y] < 82) { grades[5] = grades[5] + 1; } else if ( data[y] > 74 && data[y] < 79 ) { grades[4] = grades[4] + 1; } else if ( data[y] > 71 && data[y] < 75 ) { grades[3] = grades[3] + 1; } else if ( data[y] > 68 && data[y] < 72 ) { grades[2] = grades[2] + 1; } else if ( data[y] > 59 && data[y] < 69 ) { grades[1] = grades[1] + 1; else { //data[y] < 60: grades[0] = grades[0] + 1; } 

Does anyone know a more convenient way to handle this block of code since my switch / case idea cannot be applied? Of course, there must be a better way to do this.

+5
source share
8 answers

Use a loop. You will also need an array of the minimum data value for each class. Here is an example of untested code as an example:

 for (int i = 9; i >= 0; i--) { if (data[y] >= minDataValueForGrade[i]) { grades[i]++; break; } } 

It is short, easy to read, and makes it easy to change the values ​​corresponding to each class.

+4
source

The most obvious way to shorten your code is to get rid of unnecessary second tests:

 if (data[y] >= 92) ++grades[9]; else if (data[y] >= 89) ++grades[8]; else if (data[y] >= 85) ++grades[7]; else if (data[y] >= 82) ++grades[6]; else if (data[y] >= 80) ++grades[5]; else if (data[y] >= 75) ++grades[4]; else if (data[y] >= 72) ++grades[3]; else if (data[y] >= 69) ++grades[2]; else if (data[y] >= 60) ++grades[1]; else ++grades[0]; 
+14
source

This seems like a reasonable data-based approach:

 int grade_cutoff[] = { 59, 68, 71, 74, 79, 81, 84, 88, 91, INT_MAX }; int grade_bucket; for (grade_bucket = 0; data[y] > grade_cutoff[grade_bucket]; grade_bucket++) { /* nothing */ } grades[grade_bucket]++; 
+6
source

If you want to avoid a long series of if .. else , about which:

 int arr[] = {60, 69, 72, 75, 79, 82, 85, 89, 92}; int i = 0; while (i < sizeof arr/ sizeof *arr && data[y] < arr[i] && i++); grades[i]++; 
+2
source

You can use a simple lookup table:

 const unsigned int index[] = { 1, 1, /* ... */, 2, 2, /* ... */ }; ++grades[data[y] < 60 ? 0 : index[data[y]]]; 
+1
source

My C rusty to be true, however you can view the problem from a different perspective than the conditional.

You must (I think) be able to restructure your data so that you can implement the decision logic without (or with much less) conventions. I think something like a 2-dimensional array or lookup table. Something like that ....

0
source
 int const datum = data[y]; int const index = (datum > 59) + (datum > 68) + (datum > 71) + (datum > 74) + (datum > 79) + (datum > 81) + (datum > 84) + (datum > 88) + (datum > 91); ++ grades[index]; 

Just calculate the index.

0
source

To radically change the subject, assuming that labels can only be in the range 0..100, consider creating an array that contains the grade number for the grade:

 enum { MAX_SCORE = 100 }; static const int upper_bound[] = { 60, 69, 72, 75, 80, 82, 85, 89, 92, MAX_SCORE+1 }; enum { N_BOUNDS = sizeof(upper_bound) / sizeof(upper_bound[0]) }; int grade_for_score[MAX_SCORE + 1]; int score = 0; for (int i = 0; i < N_BOUNDS; i++) { while (score < upper_bound[i]) grade_for_score[score++] = i; } 

The compensation for the tuning work is that the evaluation processing is trivial:

 assert(data[y] >= 0 && data[y] <= MAX_SCORE); grades[grade_for_score[data[y]]++; 

This can be useful because no conditional expressions are required to process the estimates as they become available, in addition to the basic check that the estimate is in the range [0..MAX_SCORE]. Of course, it uses some data space. Of course, if the data is read from a file (or database), the I / O interaction time completely increases the sorting time, and optimization is almost pointless.

Work code:

 #include <assert.h> #include <stdio.h> int main(void) { /* Setup */ enum { MAX_SCORE = 100 }; static const int upper_bound[] = { 60, 69, 72, 75, 80, 82, 85, 89, 92, MAX_SCORE+1 }; enum { N_BOUNDS = sizeof(upper_bound) / sizeof(upper_bound[0]) }; int grade_for_score[MAX_SCORE + 1]; int score = 0; for (int i = 0; i < N_BOUNDS; i++) { while (score < upper_bound[i]) grade_for_score[score++] = i; } /* Scoring - test each score from [0..MAX_SCORE] */ int grades[N_BOUNDS] = { 0, }; int data[1]; int y = 0; for (int i = 0; i <= MAX_SCORE; i++) { data[y] = i; assert(data[y] >= 0 && data[y] <= MAX_SCORE); grades[grade_for_score[data[y]]]++; } /* Print grades */ int sum = 0; for (int i = 0; i < N_BOUNDS; i++) { sum += grades[i]; printf("Grade %d: %3d (cumulative %3d)\n", i, grades[i], sum); } return 0; } 

Note that at compile time, you could initialize the grade_for_score table rather than run it at runtime:

 /* Manually generated; not formally checked for correctness */ int grade_for_score[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; 

However, the table is easily computed from the upper bounds table, and computers are better suited to counting rights than people, so it’s better to create a table at run time.

Execution Example:

 Grade 0: 60 (cumulative 60) Grade 1: 9 (cumulative 69) Grade 2: 3 (cumulative 72) Grade 3: 3 (cumulative 75) Grade 4: 5 (cumulative 80) Grade 5: 2 (cumulative 82) Grade 6: 3 (cumulative 85) Grade 7: 4 (cumulative 89) Grade 8: 3 (cumulative 92) Grade 9: 9 (cumulative 101) 
0
source

Source: https://habr.com/ru/post/1202366/


All Articles