I\'m searching for a way to count unique digits efficiently with a one liner.
For example: given the integer 623562
, return value would be 4
I'm having a hard time believing that len(set(str(num)))
isn't fast enough for you. Here is a test that does len(set(str()))
of a random, very large number 100,000 times:
% python -m timeit -s 'import random' 'for i in range(100000): \
len(set(str(random.randint(199123212312399956789, 1000000099999999123091230000000))))'
10 loops, best of 3: 456 msec per loop
And a decent chunk of that time is just generating the random numbers! If you really need to go faster than that, I'd think you should consider an alternative language.
set
s are optimized for this creation. Unless you want to roll out your own decimal-to-string conversion (and that would take more than one line), it's the way to go.
range
only allocates memory in Python 2.x. For small numbers like 623562, the memory shouldn't be a problem. For larger numbers, use xrange
in Python 2.x or simply switch to Python 3.x, where range
generates the numbers just in time.
Here's a way that avoids creating a set each time. All but the last line are initialisation code so only happen once:
>>> from operator import or_
>>> from collections import Counter
>>> from functools import reduce
>>> bits = {str(i):2**i for i in range(10)}
>>> counts = [Counter(format(i,'b'))['1'] for i in range(2**10)]
>>> counts[reduce(or_, (bits[c] for c in str(623562)))]
4
However, it is about 3 times slower than the simple, clear, obvious len(set(str(i)))
. As usual in Python making things more complicated or trying to be excessively clever will come back and bite you on performance.