Daily Challenge #54 - What century is it?

twitter logo ・1 min read

Daily Challenge (115 Part Series)

1) Daily Challenge #1 - String Peeler 2) Daily Challenge #2 - String Diamond 3 ... 113 3) Daily Challenge #3 - Vowel Counter 4) Daily Challenge #4 - Checkbook Balancing 5) Daily Challenge #5 - Ten Minute Walk 6) Daily Challenge #6 - Grandma and her friends 7) Daily Challenge #7 - Factorial Decomposition 8) Daily Challenge #8 - Scrabble Word Calculator 9) Daily Challenge #9 - What's Your Number? 10) Daily Challenge #10 - Calculator 11) Daily Challenge #11 - Cubic Numbers 12) Daily Challenge #12 - Next Larger Number 13) Daily Challenge #13 - Twice Linear 14) Daily Challenge #14 - Square into Squares 15) Daily Challenge #15 - Stop gninnipS My sdroW! 16) Daily Challenge #16 - Number of People on the Bus 17) Daily Challenge #17 - Double Trouble 18) Daily Challenge #18 - Triple Trouble 19) Daily Challenge #19 - Turn numbers into words 20) Daily Challenge Post #20 - Number Check 21) Daily Challenge #21 - Human Readable Time 22) Daily Challenge #22 - Simple Pig Latin 23) Daily Challenge #23 - Morse Code Decoder 24) Daily Challenge #24 - Shortest Step 25) Daily Challenge #25 - Double Cola 26) Daily Challenge #26 - Ranking Position 27) Daily Challenge #27 - Unlucky Days 28) Daily Challenge #28 - Kill the Monster! 29) Daily Challenge #29 - Xs and Os 30) Daily Challenge #30 - What is the price? 31) Daily Challenge #31 - Count IPv4 Addresses 32) Daily Challenge #32 - Hide Phone Numbers 33) Daily Challenge #33 - Did you mean...? 34) Daily Challenge #34 - WeIrD StRiNg CaSe 35) Daily Challenge #35 - Find the Outlier 36) Daily Challenge #36 - Let's go for a run! 37) Daily Challenge #37 - Name Swap 38) Daily Challenge #38 - Middle Name 39) Daily Challenge #39 - Virus 40) Daily Challenge #40 - Counting Sheep 41) Daily Challenge #41 - Greed is Good 42) Daily Challenge #42 - Caesar Cipher 43) Daily Challenge #43 - Boardgame Fight Resolver 44) Daily Challenge #44 - Mexican Wave 45) Daily Challenge #45 - Change Machine 46) Daily Challenge #46 - ??? 47) Daily Challenge #47 - Alphabets 48) Daily Challenge #48 - Facebook Likes 49) Daily Challenge #49 - Dollars and Cents 50) Daily Challenge #50 - Number Neighbor 51) Daily Challenge #51 - Valid Curly Braces 52) Daily Challenge #52 - Building a Pyramid 53) Daily Challenge #53 - Faro Shuffle 54) Daily Challenge #54 - What century is it? 55) Daily Challenge #55 - Building a Pile of Cubes 56) Daily Challenge #56 - Coffee Shop 57) Daily Challenge #57 - BMI Calculator 58) Daily Challenge #58 - Smelting Iron Ingots 59) Daily Challenge #59 - Snail Sort 60) Daily Challenge #60 - Find the Missing Letter 61) Daily Challenge #61 - Evolution Rate 62) Daily Challenge #62 - Josephus Survivor 63) Daily Challenge #63- Two Sum 64) Daily Challenge #64- Drying Potatoes 65) Daily Challenge #65- A Disguised Sequence 66) Daily Challenge #66- Friend List 67) Daily Challenge #67- Phone Directory 68) Daily Challenge #68 - Grade Book 69) Daily Challenge #69 - Going to the Cinema 70) Daily Challenge #70 - Pole Vault Competition Results 71) Daily Challenge #71 - See you next Happy Year 72) Daily Challenge #72 - Matrix Shift 73) Daily Challenge #73 - ATM Heist 74) Daily Challenge #74 - Free Pizza 75) Daily Challenge #75 - Set Alarm 76) Daily Challenge #76 - Bingo! (or not...) 77) Daily Challenge #77 - Bird Mountain 78) Daily Challenge #78 - Number of Proper Fractions with Denominator d 79) Daily Challenge #79 - Connect Four 80) Daily Challenge #80 - Longest Vowel Change 81) Daily Challenge #81 - Even or Odd 82) Daily Challenge #82 - English Beggars 83) Daily Challenge #83 - Deodorant Evaporator 84) Daily Challenge #84 - Third Angle of a Triangle 85) Daily Challenge #85 - Unwanted Dollars 86) Daily Challenge #86 - Wouldn't, not Would. 87) Daily Challenge #87 - Pony Express 88) Daily Challenge #88 - Recursive Ninjas 89) Daily Challenge #89 - Extract domain name from URL 90) Daily Challenge #90 - One Step at a Time 91) Daily Challenge #91 - Bananas 92) Daily Challenge #92 - Boggle Board 93) Daily Challenge #93 - Range Extraction 94) Daily Challenge #94 - Last Digit 95) Daily Challenge #95 - CamelCase Method 96) Daily Challenge #96 - Easter Egg Crush Test 97) Daily Challenge #97 - Greed is Good 98) Daily Challenge #98 - Make a Spiral 99) Daily Challenge #99 - Balance the Scales 100) Daily Challenge #100 - Round Up 101) Daily Challenge #101 - Parentheses Generator 102) Daily Challenge #102 - Pentabonacci 103) Daily Challenge #103 - Simple Symbols 104) Daily Challenge #104 - Matrixify 105) Daily Challenge #105 - High-Sum Matrix Drop 106) Daily Challenge #106 - Average Fuel Consumption 107) Daily Challenge #107 - Escape the Mines 108) Daily Challenge #108 - Find the Counterfeit Coin 109) Daily Challenge #109 - Decorate with Wallpaper 110) Daily Challenge #110 - Love VS. Friendship 111) Daily Challenge #111 - 99 Bottles of Beer 112) Daily Challenge #112 - Functions of Integers on the Cartesian Plane 113) Daily Challenge #113 - Iterative Rotation Cipher 114) Daily Challenge #114 - Speed Control 115) Daily Challenge #115 - Look and Say Sequence

Challenge
Write a function that will return an inputted numerical year in century format. The output should have the appropriate written ending ('st','nd','rd','th') as well.

Examples
In: 2259 Out: 23rd
In: 1124 Out: 12th
In: 2000 Out: 21st

Good luck!


This challenge comes from Cpt.ManlyPink on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

twitter logo DISCUSS (22)
markdown guide
 

A reasonably short and reasonably Rusty solution:

pub fn century(year: u32) -> String {
    let century = year / 100 + 1;
    let suffix = match century % 100 {
        11 | 12 | 13 => "th",
        _ => match century % 10 {
            1 => "st",
            2 => "nd",
            3 => "rd",
            _ => "th",
        },
    };
    format!("{}{}", century, suffix)
}
 

Sometimes Rust and F# really show their common ML roots, see my solution below.

 

I used your answer as a cheatsheet of sorts. Good job! :)

 
 

F#:

module Century

let private parseYear s =
    let n = int s
    if n >= 0 then Ok n
    else Error "Year must be >= 0"

let private suffix c =
    match c % 100 with
    | 11
    | 12
    | 13 -> "th"
    | _ ->
        match c % 10 with
        | 1 -> "st"
        | 2 -> "nd"
        | 3 -> "rd"
        | _ -> "th"

let century (year : string) =
    match parseYear year with
    | Ok year ->
        let c = year / 100 + 1
        sprintf "%d%s" c (suffix c)
    | Error msg -> failwith msg

Failing on inputs < 0 was an arbitrary decision, it's easy to adopt the current code to take care of BC/AD.

Tests:

module CenturyTest

open FsUnit.Xunit
open Xunit
open Century

[<Fact>]
let ``2259``() = century "2259" |> should equal "23rd"

[<Fact>]
let ``1124``() = century "1124" |> should equal "12th"

[<Fact>]
let ``2000``() = century "2000" |> should equal "21st"

[<Fact>]
let ``0``() = century "0" |> should equal "1st"

[<Fact>]
let ``111``() = century "111" |> should equal "2nd"

[<Fact>]
let ``2245``() = century "2245" |> should equal "23rd"

[<Fact>]
let ``invalid year``() = (fun () -> century "-1" |> ignore) |> shouldFail
 

A bit of functional JS

const test = require('./tester');

const century = year => {
    if (isNaN(year)) return null;
    const nYear = Number(year);
    const cent = Math.floor(nYear / 100) + 1;
    const suffix = Math.floor(cent / 10) % 10 === 1 ? 'th'
        : cent % 10 === 1 ? 'st'
        : cent % 10 === 2 ? 'nd'
        : cent % 10 === 3 ? 'rd'
        : 'th';
    return `${cent}${suffix}`;
}

test(century, [
    {
        in: [2259],
        out: '23rd',
    },
    {
        in: [1124],
        out: '12th',
    },
    {
        in: [2000],
        out: '21st'
    },
    {
        in: [11092],
        out: '111th',
    },
]);
 

I like your approach, it looks very clean.

This is probably too fringe to matter in most contexts, but wouldn't your function return 111st for the year 11,092?

 

It would, indeed. Thanks for pointing out. Now I have fixed it and added a new test case.

OLD SOLUTION (Line 7)

const suffix = Math.floor(cent / 10) === 1 ? 'th'

UPDATED SOLUTION (Line 7)

const suffix = Math.floor(cent / 10) % 10 === 1 ? 'th'
 

F#

let whatCenture (year: int) =
    let centure = year / 100 + 1

    let suffix x =
        if (centure % 13) = 12  || (centure % 13) = 11
        then "th"
        else match x % 10 with 
                | 1 -> "st"
                | 2 -> "nd"
                | 3 -> "rd"
                | _ -> "th"

    (string centure) + (suffix centure)

 
 

Yes, yes, I know, 2000 should return "21st" century. I don't know of anyone who counts centuries like that, so my function returns them according to normal use.

const addBC = year => year < 0 ? " BC" : ""

const centurify = year => {
   const num = Math.ceil(Math.abs(year) / 100).toString()
   const suffix = num.match(/(11|12|13)$/)
      ? "th" : num.endsWith("1")
      ? "st" : num.endsWith("2")
      ? "nd" : num.endsWith("3")
      ? "rd" : "th"
   return num + suffix + addBC(year)
}
 

This may be missing a couple of special cases:

centurify(1124)
'12nd'
> centurify(1213)
'13rd'
 

It's fixed now (I think). It should also support BC centuries.

 
 

This would've been even more interesting using the strict usage of "century" ;-)

#!/usr/bin/perl
use warnings;
use strict;

sub century {
    my ($year) = @_;
    my $century = 1 + int($year / 100);
    my $suffix;
    $suffix = 'th' if grep $century == $_, 11 .. 13;
    $suffix ||= {
        1 => 'st',
        2 => 'nd',
        3 => 'rd',
    }->{ substr $century, -1 } || 'th';
    $century . $suffix
}

use Test::More tests => 6;
is century(33),    '1st';
is century(2259), '23rd';
is century(1124), '12th';
is century(2000), '21st';
is century(3199), '32nd';
is century(2423), '25th';

First handle the exceptions (i.e. 11 - 13), then just use the last digit to decide.

 

A length Javascript solution, but I did not want to divide by 100.

const century = year => {
  const yearString = year.toString();
  const n = String(year).length;
  if (n - 3 < 0) {
    console.log("0th century");
  } else {
    console.log(digitYears(yearString, n));
  }
};

const digitYears = (yearString, n) => {
  const toIntAgain = parseInt(yearString[n - 3]) + 1;
  const edges = parseInt(yearString.slice(n - 4, n - 2)) + 1;
  if (edges == 11 || edges == 12 || edges == 13) {
    return `${yearString.slice(0, n - 3)}${toIntAgain}th century`;
  } else {
    const ending = endingDetermine(toIntAgain);
    return `${yearString.slice(0, n - 3)}${toIntAgain}${ending} century`;
  }
};

const endingDetermine = digit => {
  let ending = "";
  switch (digit) {
    case 1:
      ending = "st";
      break;
    case 2:
      ending = "nd";
      break;
    case 3:
      ending = "rd";
      break;
    default:
      ending = "th";
      break;
  }
  return ending;
};

Tried it with a few different years including the edge cases.

century(11034); //111th century
century(15134); //152nd century
century(16234); //163th century
century(942); //10th century
century(2042); //21st century
century(1342); //14th century
century(1242); //13th century
century(52); //0th century
 

Ah, this one was tricker than I thought because of the edge cases.

I choose a solution in JS that lists out all the endings in an object - but since they are almost all the same, maybe I should have done something else :)

Also, since I've started recording me solving these, you can check it out here: youtube.com/watch?v=ozws2mzhqkM

const centuryName = year => {
  const endings = {
    0: 'th',
    1: 'st',
    2: 'nd',
    3: 'rd',
    4: 'th',
    5: 'th',
    6: 'th',
    7: 'th',
    8: 'th',
    9: 'th',
  }

  const century = Math.floor(year / 100) + 1
  const rem = century % 10
  const ending = [11, 12, 13].includes(century % 100) 
    ? 'th' : endings[rem]
  return `${century}${ending}`
}
 

Insert Go Pun Here

century.go

package century

import (
    "strconv"
)

// Century gives the text representation of what century the given date belongs to
func Century(date int) string {
    // if date is negative (BC), convert to positive
    if date < 0 {
        date *= -1
    }
    prefix := date/100 + 1

    var suffix string

    // if its one the weird teens centuries, suffix is "th"
    switch prefix % 100 {
    case 11, 12, 13:
        suffix = "th"
    default:
        switch prefix % 10 {
        case 1:
            suffix = "st"
        case 2:
            suffix = "nd"
        case 3:
            suffix = "rd"
        default:
            suffix = "th"
        }
    }

    return strconv.Itoa(prefix) + suffix
}

century_test.go

package century

import "testing"

func TestCentury(t *testing.T) {
    testCases := []struct {
        description string
        input       int
        expected    string
    }{
        {
            "twenty third centry",
            2259,
            "23rd",
        },
        {
            "twelfth century",
            1124,
            "12th",
        },
        {
            "twenty first century",
            2000,
            "21st",
        },
        {
            "small centry",
            24,
            "1st",
        },
        {
            "odd centry name",
            1013,
            "11th",
        },
        {
            "large odd century name",
            11013,
            "111th",
        },
        {
            "negative century",
            -2000,
            "21st",
        },
    }

    for _, test := range testCases {
        if result := Century(test.input); result != test.expected {
            t.Fatalf("FAIL: %s - Centry(%d): %s - expected '%s'", test.description, test.input, result, test.expected)
        }
        t.Logf("PASS: %s", test.description)
    }
}

 

Rust:

fn century_name(year: u32) -> String {
    let century = (year / 100) + 1;
    format!(
        "{}{}",
        century,
        match century % 10 {
            _ if century > 10 && century < 14 => "th", // teen numbers exception
            1 => "st",
            2 => "nd",
            3 => "rd",
            _ => "th",
        }
    )
}
 
Classic DEV Post from Aug 30

SELECT Post FROM Stack Overflow Questions WHERE Topic = "git" ORDER BY Votes DESC;

dev.to staff profile image
The hardworking team behind dev.to ❤️