5
\$\begingroup\$

I'm going through a basic python exercise, stumbled upon this query.

Given a non-negative number "num", return True if num is within 2 of a multiple of 10.

Here's the my solution:

def near_ten(num):
  return (num % 10) in range(8, 10) or (num % 10) in range(0, 3)

It shows "All Correct", but I'm feeling like my code is bit digressive as I have hard-coded the "numbers within 2 of a multiple of 10".

Can one please review this line if its the right approach?

\$\endgroup\$
  • 3
    \$\begingroup\$ I'm not sure I understand your solution. Multiples of 10 aren't just 0 and 10, but also 20, 30, 40, etc. \$\endgroup\$ – shadowtalker Nov 28 '17 at 13:30
  • \$\begingroup\$ You could shift the values, so you need to check only one range: return ((num + 2) % 10) in range(0, 5) or return ((num + 2) % 10) < 5 \$\endgroup\$ – Henrik Nov 28 '17 at 13:56
7
\$\begingroup\$

I would suggest you to go further in hard coding those values: I mean I would write:

def is_near_ten(num):
   return (num % 10) in [0, 1, 2, 8, 9]

You can see visually the difference (less instructions) and you can confirm that:

>>> import timeit
>>> timeit.timeit('(128 % 10) in [0, 1, 2, 8, 9]')
0.23481132300003082
>>> timeit.timeit('(128 % 10) in range(8, 10) or (128 % 10) in range(0, 3)')
1.3901589560000502

You can notice that further hard coding those values as suggested makes your function more than 5 times faster.

\$\endgroup\$
  • 1
    \$\begingroup\$ Of-course, in proper code, you'd move those hardcoded values to PSEUDO_CONSTS. \$\endgroup\$ – Mast Nov 28 '17 at 11:50
  • 4
    \$\begingroup\$ While a perfectly valid answer, I disagree with hardcoding the distances as a list. I think it would make more sense if one could dynamically set the 'close' value, e.g. is_near(number, limit). \$\endgroup\$ – Daniel Nov 28 '17 at 11:50
2
\$\begingroup\$

A hard-coded solution without lists:

def near_ten(num):
    return ((num%10) <= 2) or ((num%10) >= 8)

A generalized version, as some commenters asked for:

def near_num(num,mult,diff):
    return ((num%mult) <= diff) or ((num%mult) >= (mult-diff))

def near_ten(num):
    return near_num(num,10,2)

The times I got for this were: (using existing answers to compare against)

>>> import timeit
>>> timeit.timeit('(128%10) in range(0,3) or (128%10) in range(8,10)')
0.5436179637908936
>>> timeit.timeit('(128%10) in [0,1,2,8,9]')
0.15247392654418945
>>> timeit.timeit('(128%10) <= 2) or ((128%10) >= (10-2))')
0.11723899841308594

So, it seems a little faster than even the hard-coded list.

I thought about adding a variable to store the value of (num%mult), but figure that a smart compiler should automatically put that in a temporary variable for reuse.

\$\endgroup\$
  • \$\begingroup\$ I thought about adding a variable to store the (num%mult), but figure that a smart compiler should automatically put that in a temporary variable for reuse. So, I am curious as to opinions on how that would affect speed, memory, and (most importantly to me) readability. \$\endgroup\$ – Ghost8472 Nov 28 '17 at 16:46
  • 2
    \$\begingroup\$ I added the context from your comment in your post - Refer to the section When shouldn't I comment? on Comment everywhere. You could potentially post a new question if you have working code, and reference this post... \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ Nov 28 '17 at 16:49
  • \$\begingroup\$ @SamOnela thanks for linking to that article on commenting, I hadn't seen it yet. I went back and forth on whether to edit my post, or add a comment. I think I can argue my comment was part of "Add relevant but minor or transient information to a post" because my comment addresses an alternative style to what I advocated. I fixed your edit, as it broke the context of my post. \$\endgroup\$ – Ghost8472 Nov 28 '17 at 17:09
  • \$\begingroup\$ okay- sorry about that. \$\endgroup\$ – Sᴀᴍ Onᴇᴌᴀ Nov 28 '17 at 17:10
  • \$\begingroup\$ @SamOnela thank you. Sorry I was being snippy. I do think you are right that my comment should have been part of the post. Also, thank you for pointing out the context issues, and I will try to avoid asking new questions in my answers/comments. \$\endgroup\$ – Ghost8472 Nov 28 '17 at 17:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.