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!

Top comments (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
 
anwar_nairi profile image
Anwar

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
 
anwar_nairi profile image
Anwar • 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))