DEV Community

dev.to staff
dev.to staff

Posted on

Daily Challenge #71 - See you next Happy Year

You're saying goodbye to your friend when they say to you, "See you next happy year!" You smile and wave, saying you'll see them then. But wait, when's the next happy year anyway?

Given a year, write a function that will return the closest year you'll see your friend, the next year with all unique digits.

Years will always be represented as positive integers. It is not necessary for the year passed through the function to be a Happy one.

Examples:
nextHappyYear(7712) ==> 7801
nextHappyYear(1001) ==> 1023
nextHappyYear(2018) ==> 2019


This challenge by MrZizoScream on CodeWars was used for inspiration. 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!

Top comments (15)

Collapse
 
andre000 profile image
AndrΓ© Adriano • Edited

Javascript:

function nextHappyYear(year) {
  const nextYear = ~~year + 1;
  const isHappyYear = new Set(`${nextYear}`).size === `${year}`.length;
  if (!isHappyYear) {
    return nextHappyYear(nextYear);
  }

  return nextYear;
}

Results:

nextHappyYear(2018);
// 2019
nextHappyYear(1001);
// 1023
nextHappyYear(7712);
// 7801
Collapse
 
peledzohar profile image
Zohar Peled

Clever usage of Set!

Collapse
 
brightone profile image
Oleksii Filonenko • Edited

Elixir (now with doctests!):

defmodule Day71 do
  @doc """
  Finds the next happy year after `year`.

  iex> Day71.next_happy_year(7712)
  7801
  iex> Day71.next_happy_year(1001)
  1023
  iex> Day71.next_happy_year(2018)
  2019
  """
  @spec next_happy_year(pos_integer) :: pos_integer
  def next_happy_year(year) do
    (year + 1)
    |> Stream.iterate(&(&1 + 1))
    |> Enum.find(&happy?/1)
  end

  @doc """
  Checks if a year is a happy year.

  A year is happy if all its digits are unique.

  iex> Day71.happy?(2019)
  true
  iex> Day71.happy?(2021)
  false
  """
  @spec happy?(pos_integer) :: boolean
  def happy?(year) do
    digits = Integer.digits(year)
    Enum.uniq(digits) == digits
  end
end

And a test file (just for the sake of completeness):

defmodule Day71Test do
  use ExUnit.Case
  doctest Day71
end
Collapse
 
choroba profile image
E. Choroba

Using a regex in Perl:

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

sub next_happy_year {
    my ($year) = @_;
    1 while ++$year =~ /(.).*\1/;
    $year
}

use Test::More tests => 3;

is next_happy_year(7712) => 7801;
is next_happy_year(1001) => 1023;
is next_happy_year(2018) => 2019;
Collapse
 
aminnairi profile image
Amin • Edited

Elm

module NextHappyYear exposing (nextHappyYear)

import List exposing (length)
import String exposing (any, fromChar, fromInt, indexes)


isMultiple : List anything -> Bool
isMultiple list =
    length list > 1


nonUniqueCharacterIn : String -> Char -> Bool
nonUniqueCharacterIn string character =
    indexes (fromChar character) string
        |> isMultiple


nextHappyYear : Int -> Int
nextHappyYear year =
    let
        nextYear : Int
        nextYear =
            year + 1

        yearString : String
        yearString =
            nextYear
                |> fromInt

        nonHappyYear : Bool
        nonHappyYear =
            yearString
                |> any (nonUniqueCharacterIn yearString)
    in
    if nonHappyYear then
        nextHappyYear nextYear

    else
        nextYear

Tests

module NextHappyYearTest exposing (suite)

import Expect exposing (equal)
import NextHappyYear exposing (nextHappyYear)
import Test exposing (Test, describe, test)


suite : Test
suite =
    describe "Next happy year"
        [ test "It should return 7712 when passing 7801" <|
            \_ ->
                equal 7801 <| nextHappyYear 7712
        , test "It should return 1001 when passing 1023" <|
            \_ ->
                equal 1023 <| nextHappyYear 1001
        , test "It should return 2019 when passing 2018" <|
            \_ ->
                equal 2019 <| nextHappyYear 2018
        ]

Edit

Just realized there is a native Set module in Elm by looking at the comments made in JavaScript which is awesome, but I'll keep this as is for the record. I'm edgy anyway!

Edit2

Turns out, after an interesting talk with the folks at the Elm Slack, and some experimentations, there is no way to to Set that keeps the order of the List due to the Haskell implementation behind, preventing to have an easy solution. So this means either use an extra library (which I tend to avoid since I wanted to show a native Elm solution) or use a combination just like I did!

Collapse
 
anwar_nairi profile image
Anwar

Here is my solution using PHP:

if (!function_exists("hasUniqueDigits")) {
    function hasUniqueDigits(int $number): bool {
        $digits = str_split($number);

        return $digits === array_unique($digits);
    }
}

if (!function_exists("nextHappyYear")) {
    function nextHappyYear(int $year): int {
        $nextYear = $year + 1;

        while(!hasUniqueDigits($nextYear)) {
            $nextYear++;
        }

        return $nextYear;
    }
}

And here is my unit tests:

use PHPUnit\Framework\TestCase;

class NextHappyYearTest extends TestCase {
    public function testShouldReturnNextHappyYear() {
        $this->assertEquals(nextHappyYear(7712), 7801);
    }

    public function testShouldReturnOtherNextHappyYear() {
        $this->assertEquals(nextHappyYear(1001), 1023);
    }

    public function testShouldReturnOtherOtherNextHappyYear() {
        $this->assertEquals(nextHappyYear(2018), 2019);
    }
}

Hope you like it :)

Collapse
 
brightone profile image
Oleksii Filonenko

Rust:

fn next_happy_year(year: u32) -> u32 {
    let mut year = year + 1;
    while !happy(year) {
        year += 1;
    }
    year
}

fn happy(year: u32) -> bool {
    let mut chars = year.to_string().chars().collect::<Vec<_>>();
    chars.sort();
    let len = chars.len();
    chars.dedup();
    chars.len() == len
}

This was a strange exercise to do in Rust. Feels dirty to use conversion to string :(

Collapse
 
mbaas2 profile image
Michael Baas • Edited

APL (I'm using Dyalog APL)

Code:

{4=+/βŽ•dβˆŠβ•β΅:β΅β‹„βˆ‡β΅+1}

Tests:

     {4=+/βŽ•dβˆŠβ•β΅:β΅β‹„βˆ‡β΅+1}7712
7801
     {4=+/βŽ•dβˆŠβ•β΅:β΅β‹„βˆ‡β΅+1}1001
1023
     {4=+/βŽ•dβˆŠβ•β΅:β΅β‹„βˆ‡β΅+1}2019
2019
Collapse
 
vinniew1rus profile image
Vinnie

Simple JS solution:

function nextHappyYear(year){
    let newYear = year + 1;
    let arr = newYear.toString().split('');
    let uniq = arr.filter((item, pos) => arr.indexOf(item) == pos);
    if (uniq.length !== arr.length)
        return nextHappyYear(newYear);
    return newYear;
}
Collapse
 
vinniew1rus profile image
Vinnie • Edited

And a PHP solution:

function nextHappyYear($year){
    $newYear = $year+1;
    return strlen($newYear) == count(array_unique(str_split($newYear))) ? $newYear : nextHappyYear($newYear);
}
Collapse
 
teaglebuilt profile image
dillan teagle

quick python solution

def nextHappyYear(year):
    next_year = year + 1
    yr_list = [int(x) for x in str(year)]
    happy_year = len(set(yr_list)) == len(yr_list)
    if not happy_year:
        return nextHappyYear(next_year)

    return happy_year
Collapse
 
ignare profile image

My ugly answer. But I thought I would at least give this a go in python.


def find_happy_year(string)
    not_happy = True
    while(not_happy):
        for letter in string:
            same_same = 0
            for other_letter in string:
                if letter == other_letter:
                    same_same += 1
            if same_same > 1:
                not_happy = True
                string = str( int(string) + 1 )
                break
            else:
                not_happy = False
    print (string)
Collapse
 
brightone profile image
Oleksii Filonenko

Great, thanks! I blanked out on this for some reason :)