xyz9
xyz9

Reputation: 19

is there any faster way to do this exercise?

int function2 (const char * string1) returning the number of unique digits appearing in the string, e.g. function2 ("ab512af6kc1") -> 3.

int function2(const char* string1) {
  int zero = 0, one = 0, two = 0, three = 0, four = 0, five = 0, six = 0,
      seven = 0, eight = 0, nine = 0, counter = 0;

  for (int i = 0; i < strlen(string1); i++) {
    if (string1[i] == '0') {
      zero++;
    }
    if (string1[i] == '1') {
      one++;
    }
    if (string1[i] == '2') {
      two++;
    }
    if (string1[i] == '3') {
      three++;
    }
    if (string1[i] == '4') {
      four++;
    }
    if (string1[i] == '5') {
      five++;
    }
    if (string1[i] == '6') {
      six++;
    }
    if (string1[i] == '7') {
      seven++;
    }
    if (string1[i] == '8') {
      eight++;
    }
    if (string1[i] == '9') {
      nine++;
    }
  }
  if (zero == 1) {
    counter++;
  }
  if (one == 1) {
    counter++;
  }
  if (two == 1) {
    counter++;
  }
  if (three == 1) {
    counter++;
  }
  if (four == 1) {
    counter++;
  }
  if (five == 1) {
    counter++;
  }
  if (six == 1) {
    counter++;
  }
  if (seven == 1) {
    counter++;
  }
  if (eight == 1) {
    counter++;
  }
  if (nine == 1) {
    counter++;
  }

  return counter;
}

It's every correct in this code, but it's long a bit. Could someone help me and write SHORTER code? It's the only way that I can measure up to this exercise.

Upvotes: 0

Views: 113

Answers (5)

selbie
selbie

Reputation: 104589

Use a hash table collection class to keep track of unique digits. In this case, unordered_set will do just fine. Don't even bother converting the char to integer. You're just looking for unique chars between '0' and '9'.

#include <string>
#include <unordered_set>

size_t getUniqueDigits(const std::string& string1)
{
    std::unordered_set<char> table;
    for (char c : string1)
    {
        if ((c >= '0') && (c <= '9'))
        {
            table.insert(c);
        }
    }
    return table.size();
}

A more traditional "C" based solution that doesn't use any std:: collections or objects is to use an array to be that "set"

int getUniqueDigits(const char* string1)
{
    int table[10] = {0};
    int count = 0;
    const size_t len = (string1 != nullptr) ? strlen(string1) : 0;

    for(size_t i = 0; i < len; i++)
    {
        char c = string1[i];
        if ((c >= '0') && (c <= '9'))
        {
            table[c - '0'] = 1;
        }
    }

    for (char j = '0'; j <= '9'; j++)
    {
        count += table[j];
    }

    return count;
}

Upvotes: 1

anatolyg
anatolyg

Reputation: 28320

To shorten your code, use an array instead of 10 individual variables:

int digits[10] = {0}; // instead of int zero = 0, one = 0, ...

To check whether a char is a representation of a digit, use isdigit:

if (isdigit(string1[i])) // instead of if (string1[i] == '0'), if (string1[i] == '1'), ...

The only non-trivial part is to convert a char to the corresponding int:

string1[i] - '0'

This code subtracts the character code of 0 (usually 48) from the character code of a digit (usually 49 for 1, 50 for 2, ..., 57 for 9). The result is an index to your array of counters.

So, to increase the proper array element, use the following code:

digit = string1[i] - '0';
digits[digit]++; // instead of zero++, one++, ...

After the code goes over the input string, count the number of digits which appeared once:

int counter = 0;
for (digit = 0; digit < 10; ++digit)
{
    if (digits[digit] == 1)
        ++counter;
}

Upvotes: 1

Tony Barletta
Tony Barletta

Reputation: 385

I think you already have many good solutions.

Here is mine version anyway

int function2(const char* string1) {
    int count[10] = {0};
    int counter = 0;
    int i;
    for(i = 0; i < strlen(string1); i++)
        int a = (++count[string1[i]-'0']);
        if(a == 1)counter++;
        if(a == 2)counter--;
    return counter;
}

I haven't tried it. Hope there is no error

Edit: I tried it. It seems to work fine now.

Upvotes: 0

Vlad from Moscow
Vlad from Moscow

Reputation: 311156

Just use an ordinary array as for example in this demonstrative program

#include <iostream>

size_t unique_digits( const char *s )
{
    unsigned char digits[10] = { 0 };

    for ( ; *s; ++s )
    {
        if ( '0' <= *s && *s <= '9' )
        {
            if ( digits[*s - '0'] != 2 ) ++digits[*s - '0'];
        }
    }

    size_t count = 0;

    for ( unsigned char c : digits ) count += c == 1;

    return count;
}

int main() 
{
    std::cout << unique_digits( "ab512af6kc1" ) << '\n';

    return 0;
}

The program output is

3

Or you can declare the array of the element type size_t. In this case the function will look the following way

#include <iostream>

size_t unique_digits( const char *s )
{
    size_t digits[10] = { 0 };

    for ( ; *s; ++s )
    {
        if ( '0' <= *s && *s <= '9' )
        {
            ++digits[*s - '0'];
        }
    }

    size_t count = 0;

    for ( unsigned char c : digits ) count += c == 1;

    return count;
}

int main() 
{
    std::cout << unique_digits( "ab512af6kc1" ) << '\n';

    return 0;
}

Upvotes: 0

KamilCuk
KamilCuk

Reputation: 142005

You can use an array instead of 10 variables. Calculate the index in the array by converting the character to an integer.

int function2(const char *in) {
   // Array to hold digits occurence counts.
   unsigned digits[10]{};
   // Iterate over the characters in input.
   // Better (auto i : std::string_view(in)) in C++17.
   for (auto i = in; *i; ++i) {
        if (isdigit(*i)) {
            // Increment the proper digit index.
            digits[*i - '0']++;
        }
   }
   int count = 0;
   // Go through digit occurences.
   for (auto i : digits) {
      // If the digit occurred only once.
      if (i == 1) {
         // Increment the count.
         count++;
      }
   }
   return count;
}

Upvotes: 1

Related Questions