user123
user123

Reputation: 71

C language switch-case: avoiding a case after used once

I'm trying a challenge where I need to get a random number, and print the sum of the digits inside the number without duplicates: for example, 123 will print 6 ( 1 + 2 + 3 ), and 32111 will do the same ( because we don't add duplicates to our sum, the sum of this number is similar to the sum of 123. )

In my solution I thought about using switch case for each number, and use a flag that its value is one, than in each case I add 1 to the flag, and when the flag is 2 I add the number to the sum, but I don't know how to avoid a case after it happend, which if I see it correctly will avoid me using multiple flags for each number (because if we could avoid a case after it happend, i just could set the flag back to one after the switch and do all the process again )

can you help me out? thanks a lot!

#include <stdio.h>

#define TEN 10
#define NINE 9
#define EIGHT 8
#define SEVEN 7
#define SIX 6
#define FIVE 5
#define FOUR 4
#define THREE 3
#define TWO 2
#define ONE 1

int main(void)
{
    int answer = 0, i = 0, remain = 0, sum = 0, flag = 1;
    printf("Enter a number: ");
    scanf("%d", &answer);
    while(answer >= ONE)
    {
        remain = answer % TEN;
        answer /= TEN;
        printf("%d\n", remain);  
        switch (remain)
        {
        case ONE:
        {
            flag++;
            if (flag == TWO)
            {
                sum = sum + ONE;
            }
            break;
        }
        case TWO:
        {
            flag++;
            if (flag == TWO)
            {
                sum = sum + TWO;
            }
            break;
        }
        case THREE:
        {
            flag++;
            if (flag == TWO)
            {
                sum = sum + THREE;
            }
            break;
        }
        case FOUR:
        {
            flag++;
            if (flag == TWO)
            {
                sum = sum + FOUR;
            }
            break;
        }
        case FIVE:
        {
            flag++;
            if (flag == TWO)
            {
                sum = sum + FIVE;
            }
            break;
        }
        case SIX:
        {
            flag++;
            if (flag == TWO)
            {
                sum = sum + SIX;
            }
            break;
        }
        case SEVEN:
        {
            flag++;
            if (flag == TWO)
            {
                sum = sum + SEVEN;
            }
            break;
        }
        case EIGHT:
        {
            flag++;
            if (flag == TWO)
            {
                sum = sum + EIGHT;
            }
            break;
        }
        case NINE:
        {
            flag++;
            if (flag == TWO)
            {
                sum = sum + NINE;
            }
            break;
        }
        default:
        {

        }

    }

}
printf("The sum of the number is: %d", sum);
return 0;

}

Upvotes: 2

Views: 596

Answers (2)

Minn
Minn

Reputation: 6134

Try using a bitmask representing each case. The main idea is to keep track for each number (from 0 to 9) using only one integer. Some bit of this single integer can be used as to find whether this number was seen before or not. If the bit is 0 then the corresponding number is seen for the first time (and we now set the bit to 1), and if we see that the bit is already 1, then we don't add it into our final sum.

int mask = 0;

switch (remain) {
case 1: // 001
    if ((mask & 1) == 0) { // 1 = 1 << 0
        sum += 1;
        mask |= 1;
    }
    break;
...
case 3: // 100
    if ((mask & 4) == 0) { // 4 = 1 << 2
        sum += 3;
        mask |= 4;
    }
    break;
...
case n:
    if ((mask & k) == 0) { // k = 1 << (n-1)
        sum += n;
        mask |= k;
    }
    break;
...

Now you can see a pattern in the last case I used, we can simplify this switch-case into a single if statement.

int mask = 0;
int sum = 0;
while (answer) {
    remain = answer % 10;
    answer /= 10;
    int offset = remain;
    int flag = 1 << offset;
    if ((mask & flag) == 0) {
        sum += remain;
        mask |= flag;
    }
 }
 // sum contains the required answer

Each bit represents one of the cases, since you have only 10 cases this is the most efficient way to track the flags as you have more than 10 bits for an integer and it will be wastage to have a separate boolean flag for 0 to 9.

Upvotes: 1

Stephan Lechner
Stephan Lechner

Reputation: 35154

A case-term is a compile time constant, so you cannot "disable" it at runtime at the c language level. You would have to introduce a separate flag for each digit then.

I'd say - and have a look at you code - the switch-case approach is not the best as you duplicate a lot of similar code. A much easier way would be to have an array of 10 ints, each standing for a particular digit, and once a digit is encountered, set the respective array element to 1. At the end sum up in a loop.

If you have troubles getting this approach running, don't hesitate to ask again...

Upvotes: 0

Related Questions