DEV Community

dev.to staff
dev.to staff

Posted on

Daily Challenge #61 - Evolution Rate

Write a function getEvolutionRateMessage which takes two numbers before & after. The before value is the initial value of the evolution. The after value is the value after its evolution. An evolution can be calculated as follows:

evolution = (after - before) / before * 100

This function will return a string such that there are three possible outputs:
"A positive evolution of X%."
"A negative evolution of Y%."
"No evolution."

Examples:

getEvolutionRateMessage 11.29 45.79
getEvolutionRateMessage 95.12 66.84
getEvolutionRateMessage 0 27.35
getEvolutionRateMessage 41.26 0
getEvolutionRateMessage 1.26 1.26

"A positive evolution of 306%."
"A negative evolution of 30%."
"A positive evolution of 2735%."
"A negative evolution of 4126%."
"No evolution."


This challenge comes from aminnairi here on DEV. Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Discussion (26)

Collapse
savagepixie profile image
SavagePixie • Edited

Some JavaScript.

const getEvolutionRateMessage = (before, after) => {
   const evolution = before == 0 ? after * 100
   : after == 0 ? -before * 100
   : Math.round((after - before) / before * 100)

   return evolution == 0 ? "No evolution."
   : evolution > 0 ? `A positive evolution of ${evolution}℅.`
   : `A negative evolution of ${Math.abs(evolution)}%.`
}
Collapse
aminnairi profile image
Amin

Hi there, nice and short solution! I believe the case for the values 0 & 27.35 wont give what you expected. But you are in the right path for sure.

Collapse
savagepixie profile image
SavagePixie

Fixed!

Collapse
colorfusion profile image
Melvin Yeo

I wrote it in Python, kept it as short as possible while maintaining clarity. 😎

def getEvolutionRateMessage(before, after):
    if before == after:
        return "No evolution"

    polarity = "positive" if after > before else "negative"
    evo_rate = round(abs(after - before) * 100 / (before if before != 0 and after != 0 else 1))

    return f"A {polarity} evolution of {evo_rate}%"
Collapse
aminnairi profile image
Amin

Neat! I like what they did with this new string interpolation thing in Python.

I Didn't know it was called a polarity. Learning new things every day. Yay!

Collapse
khalyomede profile image
Khalyomede

Since no one proposed a PHP solution, here I am!

if (!function_exists("getEvolutionRate")) {
    function getEvolutionRate(float $before, float $after): float {
        if ($before === 0.0) {
            return $after * 100;
        }

        if ($after === 0.0) {
            return -($before * 100);
        }

        return round(($after - $before) / $before * 100);
    }
}

if (!function_exists("getEvolutionRateMessage")) {
    function getEvolutionRateMessage(float $before, float $after): string {
        $evolutionRate = getEvolutionRate($before, $after);
        $evolutionRateToDisplay = abs($evolutionRate);
        $direction = $evolutionRate > 0 ? "positive" : "negative";

        return $evolutionRate === 0.0 ? "No evolution" : "A $direction evolution of $evolutionRateToDisplay%";
    }
}

getEvolutionRate() unit tests:

use PHPUnit\Framework\TestCase;

class GetEvolutionRateTest extends TestCase
{
    public function testShouldReturnPositiveRate()
    {
        $this->assertEquals(getEvolutionRate(11.29, 45.79), 306);
    }

    public function testShouldReturnOtherPositiveRate()
    {
        $this->assertEquals(getEvolutionRate(0, 27.35), 2735);
    }

    public function testShouldReturnNegativeRate()
    {
        $this->assertEquals(getEvolutionRate(95.12, 66.84), -30);
    }

    public function testShouldReturnOtherNegativeRate()
    {
        $this->assertEquals(getEvolutionRate(41.26, 0), -4126);
    }

    public function testShouldReturnZeroEvolution()
    {
        $this->assertEquals(getEvolutionRate(1.26, 1.26), 0);
    }
}

getEvolutionRateMessage() unit tests:

use PHPUnit\Framework\TestCase;

class GetEvolutionRateMessageTest extends TestCase
{
    public function testShouldReturnPositiveRateMessage()
    {
        $this->assertEquals(getEvolutionRateMessage(11.29, 45.79), "A positive evolution of 306%");
    }

    public function testShouldReturnOtherPositiveRateMessage()
    {
        $this->assertEquals(getEvolutionRateMessage(0, 27.35), "A positive evolution of 2735%");
    }

    public function testShouldReturnNegativeRateMessage()
    {
        $this->assertEquals(getEvolutionRateMessage(95.12, 66.84), "A negative evolution of 30%");
    }

    public function testShouldReturnOtherNegativeRateMessage()
    {
        $this->assertEquals(getEvolutionRateMessage(41.26, 0), "A negative evolution of 4126%");
    }

    public function testShouldReturnZeroEvolutionMessage()
    {
        $this->assertEquals(getEvolutionRateMessage(1.26, 1.26), "No evolution");
    }
}
Collapse
aminnairi profile image
Amin

I love those guards you are puting in your code. Really makes me want to go back and do PHP with you like the good ol'times!

Collapse
khalyomede profile image
Khalyomede • Edited

Let's do a side project together

Come come

Collapse
dak425 profile image
Donald Feury

All this talk of evolution makes me want to Go play Pokemon again. Holy crap I haven't played that in a long time!

rate.go

package evolution

import "fmt"

const (
    negative string = "A negative evolution of %.f%%."
    positive string = "A positive evolution of %.f%%."
    neutral  string = "No evolution."
)

// Rate indicates the evolution percentage based on the before and after values
func Rate(before float64, after float64) string {
    if before == 0 {
        return fmt.Sprintf(positive, after*100)
    }

    if after == 0 {
        return fmt.Sprintf(negative, before*100)
    }

    rate := (after - before) / before * 100

    if rate > 0 {
        return fmt.Sprintf(positive, rate)
    }

    if rate < 0 {
        return fmt.Sprintf(negative, rate*-1)
    }

    return neutral
}

rate_test.go

package evolution

import "testing"

type testCase struct {
    description string
    input       []float64
    expected    string
}

func TestRate(t *testing.T) {
    testCases := []testCase{
        {
            "a positive evolution rate",
            []float64{11.29, 45.79},
            "A positive evolution of 306%.",
        },
        {
            "a negative evolution rate",
            []float64{95.12, 66.84},
            "A negative evolution of 30%.",
        },
        {
            "zero before value",
            []float64{0, 27.35},
            "A positive evolution of 2735%.",
        },
        {
            "zero after value",
            []float64{41.26, 0},
            "A negative evolution of 4126%.",
        },
        {
            "same before and after values",
            []float64{1.26, 1.26},
            "No evolution.",
        },
    }

    for _, test := range testCases {
        if result := Rate(test.input[0], test.input[1]); result != test.expected {
            t.Fatalf("FAIL: %s - Rate(%+v): %s - expected: %s", test.description, test.input, result, test.expected)
        }
        t.Logf("PASS: %s", test.description)
    }
}

Collapse
aminnairi profile image
Amin

I always love your take at these challenges in Go. I should get started soon. Looking sharp as always!

And yes, Pokemon is just timelessly good. I could play it all my life haha!

Collapse
dak425 profile image
Donald Feury

Ah shucks, I am humbled by the praise.

You should, Go is a very easy language to pick up and use.

Only part that may require a little more effort to understand is the concurrency related features of it but just pick those up as you need them.

Collapse
craigmc08 profile image
Craig McIlwrath

Haskell:

getEvolutionRateMessage :: Double -> Double -> String
getEvolutionRateMessage before after
  | evol > 0  = "A positive evolution of " ++ show evol ++ "%."
  | evol == 0 = "No evolution."
  | evol < 0  = "A negative evolution of " ++ show (0-evol) ++ "%." 
  where evol = (after - before) / before * 100
Collapse
aminnairi profile image
Amin

I long awaited this one. Haha!

Collapse
cgty_ky profile image
Cagatay Kaya

Here is a Javascript arrow function, that uses nested ternary operators. Someone probably already posted this answer, but hey main point is that I took the challenge and solved by myself.

const getEvolutionRateMessage = (before, after) => {
  const rate = Math.round(
    (((after == 0 ? -before * before + before : after) - before) /
      (before == 0 ? 1 : before)) *
      100
  );
  return rate == 0
    ? "No evolution."
    : rate > 0
    ? `A positive evolution of ${rate}%.`
    : `A negative evolution of ${-1 * rate}%.`;
};
Collapse
aminnairi profile image
Amin

Thanks for showing us your solution. What's important is what you achieve at the end of the day!

Collapse
choroba profile image
E. Choroba • Edited

Perl solution. I still don't understand how the values are computed for zeroes, but it passes the tests :-)

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

sub get_evolution_rate_message {
    my ($before, $after) = @_;
    return 'No evolution.' if $before == $after;
    return sprintf 'A %s evolution of %.0f%%.',
        qw(_ negative positive)[ $before <=> $after ],
        abs(($before - ($after || ($before+$before ** 2)))
            * 100 / ($before || 1))
}

use Test::More tests => 5;

is get_evolution_rate_message(11.29, 45.79), 'A positive evolution of 306%.';
is get_evolution_rate_message(95.12, 66.84), 'A negative evolution of 30%.';
is get_evolution_rate_message(0, 27.35),     'A positive evolution of 2735%.';
is get_evolution_rate_message(41.26, 0),     'A negative evolution of 4126%.';
is get_evolution_rate_message(1.26, 1.26),   'No evolution.';
Collapse
aminnairi profile image
Amin

Imagine that instead of going from 0 to 27.35, you are going from 0.0000000001 to 27.35. I think you'll have your answer here. 😉

Collapse
cvanpoelje profile image
cvanpoelje • Edited

My javascript solution :

const getEvolutionRateMessage = (before, after) => {
  evolution =
    before > 0 ? ((after - before) / before) * 100 : (after - before) * 100;
  return evolution === 0
    ? "No Evolution"
    : `A ${evolution > 0 ? "Positive" : "Negative"} evolution of ${Math.abs(
        evolution
      ).toFixed(2)}%`;
}
Collapse
avalander profile image
Avalander • Edited

My knowledge of statistics is a bit rusty (yet I didn't use rust for this challenge), but I think that an increase from 0 to anything is basically an infinite rate and a decrease from anything to 0 is a negative 100% rate, so I disagree with the examples 3 and 4 and have written my solution accordingly.

Haskell, of course

get_rate :: Double -> Double -> String
get_rate before after
  | before == after = "No evolution."
  | before == 0     = "Infinite evolution."
  | evolution < 0   = "A negative evolution of " ++ (show' . abs) evolution ++ "%."
  | otherwise       = "A positive evolution of " ++ show' evolution ++ "%."
  where
    evolution = (after - before) * 100 / before
    show'     = show . round
    -- show_abs = show' . abs -- Hmm, maybe not the best name ever, let's leave it out.

Output

get_rate 11.29 45.79 -- "A positive evolution of 306%."
get_rate 95.12 66.84 -- "A negative evolution of 30%."
get_rate 0 27.35     -- "Infinite evolution."
get_rate 41.26 0     -- "A negative evolution of 100%."
get_rate 1.26 1.26   -- "No evolution."
Collapse
devparkk profile image
Dev Prakash
def getEvolutionratemessage (before , after) :
    try :
        evolution = (after - before ) / before * 100 
    except ZeroDivisionError : 
        return "can't divide by zero " 

    if evolution > 0 :
        statement = f"A Positive evolution of {round(evolution)}%"
    elif evolution < 0:
        statement = f"A Negative evolution of {round(evolution)}%"
    else :
        statement = f"No evolution"
    return statement 

print (getEvolutionratemessage(95.12 , 66.84))

Collapse
matrossuch profile image
Mat-R-Such

python

def getEvolutionRateMessage(before,after):
    if before == 0 and after == 0:  return "No evolution."
    evolution = after * 100 if before == 0 else  before * 100 if after == 0 else round(((after-before) / before)*100)
    return "A positive evolution of "+str(int(evolution))+'%' if before<after else "A negative evolution of "+str(int(evolution*-1) if evolution <0 else int(evolution))+'%' if before > after else "No evolution."
Collapse
devparkk profile image
Dev Prakash
Collapse
colorfusion profile image
Melvin Yeo

The code will throw an error if you pass in the following parameters
getEvolutionRateMessage 0 27.35 as you're dividing by 0.

Collapse
devparkk profile image
Dev Prakash

Oyeeeeee
Thanks a lot , man
I appreciate it ...
Can u help me with how to publish my codes here in comment section ...
I don't really understand this markdown and all ...

Thread Thread
aminnairi profile image
Amin

Hi Prakash, you can refer to this link to see how code syntax highlighting works in markdown.

Thread Thread
devparkk profile image
Dev Prakash

Thank you