CodeWars Python Challenge: Does my number look big in this?

You up for another Code Wars Python Challenge?

Today I am doing the 6 kyu challenge "Does my number look big in this?".

This one we need to analyze an incoming number to see if it is a Narcissistic number. This is the first time hearing about such a number for me, but basically you sum all the digits after they have been raised to the power of the number of digits in the number. If this result equals the number, then it is a narcissistic number. ¯\_(ツ)_/¯ but ok.

Let's break this down into smaller problems.

  • Iterate over the digits
  • Determine how many digits in the input
  • Raise each digit by the number of digits
  • Sum these result of these operations
  • Compare the sum to the original number
  • Return boolean

A lot of steps, but each one is pretty easy on their own.

Let's give it a go starting with the iteration. We have done this quite a few times by now you should have this down.

You may try to do a simple for loop over the digits but realized you can not do this to a number.

def narcissistic( value ):
    for digit in value:
        pass

Let's turn it into a string first.

def narcissistic( value ):
    for digit in str(value):
        pass

Let's get the length of the digits next, and store that.

def narcissistic( value ):
    number_of_digits = len(str(value))

    for digit in str(value):
        pass

Next we should want to keep some sort of variable to work up our sum.

def narcissistic( value ):
    number_of_digits = len(str(value))
    sum = 0

    for digit in str(value):
        pass

We don't have any usable output to test with, so let's keep going. At this point let's start doing something in our for loop, raise the digit to the power of number_of_digits.

def narcissistic( value ):
    number_of_digits = len(str(value))
    sum = 0

    for digit in str(value):
        sum += int(digit)**number_of_digits

We have to convert the digit back to an int because we previously casted it as a string. ** is the operator for raising to the nth power. += is a short hand operator (syntactical sugar) for x = x + y removing the second x from the equation.

One thing I want to touch on here is the naming of variables. I do not like the python standard for variables using an underscore between words, I much prefer camelCase. You need to use the accepted standard for the language you are working. It is important for consistency and working with others code.

I think we are just about done, we just have one last thing. Let's return an evaluation if our sum matches the input.

def narcissistic( value ):
    number_of_digits = len(str(value))
    sum = 0

    for digit in str(value):
        sum += int(digit)**number_of_digits
        
    return sum == value

Looking good! Let's test against the full suite of tests.

Still good, so we have a working solution.

Let's look at the ideal solutions.

I want to talk a bit about the first one. It is obviously a lot smaller than ours. Is it better though? Maybe, maybe not.

It does use a list comprehension with a list as a return, this is very pythonic and preferred when writing Python code. It makes for a very concise function but we have two issues.

It's a bit more difficult to read and it is slower than our solution (potentially).

Both solutions require us to calculate the number of digits for the input value. If this operation is slow and expensive, the top solution repeats this operation for every digit in the input. This could cause a noticeable performance problem if the code is executed frequently.

Our solution first completes this operation and stores it. In this case, the len() function is very fast and won't create any noticeable overhead. What if this function is run 1M times in a row? Even a simple function like len() run 2-10+ times for every use of this function can slow things down a bit.

In this situation, it likely won't matter at all, but this is something you need to keep in mind when trying to optimize your code. You also don't want to spend too much time trying to optimize your code on your first pass. Just avoid obvious performance traps. After all "Premature optimization is the root of all evil". Although this statement has been challenged and why I like to suggest avoiding obvious performance traps and try to always think ahead of where you may have issues.

Code Wars Python Challenge Series


Securely chat with me on Keybase

Why you should vote me as witness

i

Sort:  

Hi Mark i am a programmer in SQL. Thanks to you i know the CodeWars Page and i result me awesome in did. Later i did some lessons on the page with SQL and i am interested in learn Phyton. You consider that CodeWars page is the better place to learn this language from zero? Thanks from now for your response!

Code Wars isn't good for learning from zero as there is no training, it is more of a self challenge site. Code Wars does have a SQL track where you can do SQL challenges.

If you want to learn from scratch I recommend looking at Code Combat if you want a really gentle introduction, otherwise a course from Udemy by Jose Portilla, Andrew Mead, or Maximilian Schwarzmüller (most Udemy courses suck, but they are really good) or Code Academy.

Thanks very much for your answer Mark!

I used to do challenges there but for javascript, haven't been on Code Wars for well over a year, tnx for the reminder. Also, I always try to make one-liners.

In JS it should look smth like this

function narcissistic (val){
return val === [...val.toString()].reduce((x,y,z,arr) => parseInt(x) + y**arr.length);
}

I prefer readable code than clever one liners.

I 100% agree with that for work-related coding. But for challenges, I try to do it as minimized as I'm able to.