List comprehension creating too many of each variable

I have been trying to make code that generates every number in a range that has non-unique digits, for example; 11 has non unique digits as 1 repeats twice.
My code:

nonUniqueNums = [i for i in range(10 ** n) for j in str(i) if str(i).count(j) >= 2]

To run this you just set n to whatever you wish(for your computer’s sake, I would recommend not going over 5.

My problem is that when it generates the list, each element is there as often as the number of its digits. I know that I could use remove elements manually, but how can I generate the list in such a way that I don’t have to do this?

P.S. the problem that I described in the last paragraph only affects it if n is larger than 2.

That is becuase you have two for loops, one for i and one of j.

If you do not need to use a list comprehension then use a normal for loop.
If it must be a comprehension then change the algorithm so that you do not need the for j. For example use a function instead.

The duplication occurs in the second for loop (for j in str(i)), where you are taking a count for each digit character of str(i), which is a list, and putting that in a list, and for every digit with a digit count >= 2 then you will end up with that many copies of i: when i is 11 this means you end up with two 11s in the outer list, when i is 22 you end up with two 22s, and so on. You need to take j from the digit set of i, so this would be:

nonUniqueNums = [i for i in range(10 ** n) if any(str(i).count(j) >= 2 for j in set(str(i)))]

The smallest value of n for which this list is non-empty is 2. For n = 2 this gives me:

>>> [i for i in range(10 ** 2) if any(str(i).count(j) >= 2 for j in set(str(i)))]
[11, 22, 33, 44, 55, 66, 77, 88, 99]

Thank you very much!

1 Like

This reminds of two interesting sequences:

  1. This OEIS sequence of positive integers where the k-th element occurs k times: so 1 occurs once, 2 occurs twice, 3 occurs thrice (in that order) etc.
  2. And this one, although not quite the same as your problem, but kind of related: Champernowne’s constant for base 10.
1 Like

A simple version would be

nonUniqueNums = [i for i in range(10 ** n) if len(set(str(i))) < len(str(i))]
3 Likes

And you could probably shave a bit off the speed by not doing str(i) twice:

nonUniqueNums = []
for i in range(10 ** n):
    stri = str(i)
    if len(set(stri)) < len(stri):
        nonUniqueNums.append(i)

I haven’t timed this, but it would probably be a bit faster.

Did they say they want 1122 in the result twice?

Just another attempt for speed:

nonUniqueNums = [
    i
    for k in range(1, n)
    for i in range(10**k, 10**(k+1))
    if len(set(str(i))) <= k
]

OK, yes, numbers with multiple repeating digit groups, e.g. xxyy, can be excluded by using any to including any number where any one digit repeats more than once (if that was what the poster wants):

nonUniqueNums = []
for i in range(10 ** n):
    s = str(i)
    if any(s.count(j) >= 2 for j in set(s)):
        nonUniqueNums.append(i)

For n = 4 this will exclude duplicates of numbers of the form xxyyy, for n = 5 numbers of the form xxyyy and xxxyy etc.

The for loop version runs faster for me.