-3

There is this "Don't give me five!" kata on codewars. (https://www.codewars.com/kata/dont-give-me-five/train/python).

Here's what you gotta do: "In this kata you get the start number and the end number of a region and should return the count of all numbers except numbers with a 5 in it. The start and the end number are both inclusive!".

I've solved it in an ugly way, which I'm not posting here. What I'm showing is the solution of one of the users. It looks smooth, but I do not understand why it works.

def dont_give_me_five(start,end):
    return sum('5' not in str(i) for i in range(start, end + 1))

I always thought that sum() sums the values, not the indexes. And if I'm right, "i" should be a value, not an index. But if it is, why does this solution work?

martineau
  • 119,623
  • 25
  • 170
  • 301
Serenity13
  • 13
  • 1
  • "What I'm showing is the solution of one of the users." - Why don't you ask that user? – TigerhawkT3 Dec 22 '16 at 08:21
  • `sum` sums whatever is inside, it doesn't transform indices into values or anything magical. Try `print(['5' not in str(i) for i in range(start, end + 1)])`. – Alex Hall Dec 22 '16 at 08:23
  • You need to `sum(i for i in range(start, end + 1))` and filter `if '5' not in str(i)`. See [generator comprehension](https://stackoverflow.com/questions/364802/generator-comprehension). – Peter Wood Dec 22 '16 at 08:34
  • Thx for help, guys. Much appreciated. – Serenity13 Dec 22 '16 at 08:39

1 Answers1

2

sum() is adding the values, those produced by a generator expression. And those values happen to be booleans, so True and False. In Python, the bool type is a subclass of int and False has an integer value of 0, True an integer value of 1.

The expression that produces the boolean values is '5' not in str(i), which is evaluated for each of the iterations of the for i in range(start, end + 1) loop. So for every i in the range from start to end inclusive, it counts the number of those values that do not have the digit 5 in them:

>>> for i in range(495, 502):
...     print('{:2d} -> {} == {}'.format(i, '5' not in str(i), int('5' not in str(i))))
...
495 -> False == 0
496 -> True == 1
497 -> True == 1
498 -> True == 1
499 -> True == 1
500 -> False == 0
501 -> False == 0
>>> sum('5' not in str(i) for i in range(495, 502))
4
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343