janejoj
janejoj

Reputation: 83

How can I keep only non-zero digits from an integer?

I am currently using the code below that removes all digits equal to zero from an integer.

int removeZeros(int candid)
{
     int output = 0;
     string s(itoa(candid));
     for (int i = s.size(); i != 0; --i)
     {
         if (s[i] != '0') output = output * 10 + atoi(s[i]);
     }
     return output;
}

The expected output for e.g. 102304 would be 1234.

Is there a more compact way of doing this by directly working on the integer, that is, not string representation? Is it actually going to be faster?

Upvotes: 6

Views: 1884

Answers (7)

g24l
g24l

Reputation: 3125

You could try something like this:

template<typename T> T nozeros( T const & z )
{
  return z==0 ? 0 : (z%10?10:1)*nozeros(z/10)+(z%10);
}

If you want to take your processing one step further you can do a nice tail recursion , no need for a helper function:

template<typename T> inline T pow10(T p, T res=1)
{
  return p==0 ? res : pow10(--p,res*10);
}

template<typename T> T nozeros( T const & z , T const & r=0, T const & zp =0)
{
  static int digit =-1;
  return not ( z ^ r ) ? digit=-1, zp : nozeros(z/10,z%10, r ? r*pow10(++digit)+zp : zp);
}

Here is how this will work with input 32040

Ret, z, r, zp, digits

-,32040,0,0, -1

-,3204,0,0, -1

-,320,4,0,0, -1

-,32,0,4,4, 0

-,3,2,4, 0

-,0,3,24, 1

-,0,0,324, 2

324,-,-,-, -1

Integer calculations are always faster than actually transforming your integer to string, making comparisons on strings, and looking up strings to turn them back to integers.

The cool thing is that if you try to pass floats you get nice compile time errors.

I claim this to be slightly faster than other solutions as it makes less conditional evaluations which will make it behave better with CPU branch prediction.

Upvotes: 1

JaeJun LEE
JaeJun LEE

Reputation: 1334

If C++11 is available, I do like this with lambda function:

int removeZeros(int candid){
    std::string s=std::to_string(candid);
    std::string output;
    std::for_each(s.begin(), s.end(), [&](char& c){ if (c != '0') output += c;});
    return std::stoi(output);
}

Upvotes: 1

Kishan Kumar
Kishan Kumar

Reputation: 333

No string representation is used here. I can't say anything about the speed though.

int removezeroes(int candid)
{
    int x, y = 0, n = 0;

    // I did this to reverse the number as my next loop 
    // reverses the number while removing zeroes.
    while (candid>0)
    {
        x = candid%10;
        n = n *10 + x;
        candid /=10;
    }
    candid = n;
    while (candid>0)
    {
        x = candid%10;
        if (x != 0)
            y = y*10 + x;
        candid /=10;
    }
    return y;
}

Upvotes: 1

rondo
rondo

Reputation: 63

int number = 9042100;
stringstream strm;
strm << number;
string str = strm.str();
str.erase(remove(str.begin(), str.end(), '0'), str.end());
number = atoi(str.c_str());

Upvotes: 1

user743382
user743382

Reputation:

For maintainability, I would suggest, don't work directly on the numeric value. You can express your requirements in a very straightforward way using string manipulations, and while it's true that it will likely perform slower than number manipulations, I expect either to be fast enough that you don't have to worry about the performance unless it's in an extremely tight loop.

int removeZeros(int n) {
  auto s = std::to_string(n);
  s.erase(std::remove(s.begin(), s.end(), '0'), s.end());
  return std::stoi(s);
}

As a bonus, this simpler implementation handles negative numbers correctly. For zero, it throws std::invalid_argument, because removing all zeros from 0 doesn't produce a number.

Upvotes: 6

Joan Esteban
Joan Esteban

Reputation: 1021

A fixed implementation of g24l recursive solution:

template<typename T> T nozeros(T const & z)
{   
  if (z == 0) return 0;
  if (z % 10 == 0) return nozeros(z / 10);
  else return (z % 10) + ( nozeros(z / 10) * 10);
}

Upvotes: 0

selbie
selbie

Reputation: 104539

Here's a way to do it without strings and buffers.

I've only tested this with positive numbers. To make this work with negative numbers is an exercise left up to you.

int removeZeros(int x)
{
    int result = 0;
    int multiplier = 1;
    while (x > 0)
    {
        int digit = x % 10;
        if (digit != 0)
        {
            int val = digit * multiplier;
            result += val;
            multiplier *= 10;
        }
        x = x / 10;
    }

    return result;
}

Upvotes: 6

Related Questions