loading...

Daily Challenge #71 - See you next Happy Year

thepracticaldev profile image dev.to staff ・1 min read

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!

Discussion

pic
Editor guide
Collapse
andre000 profile image
André Adriano

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

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
citizen428 profile image
Michael Kohl

A slightly simpler version (essentially my F# one):

def next_happy_year(year) do
  (year + 1)
  |> Stream.iterate(&(&1 + 1))
  |> Enum.find(&happy?/1)
end
Collapse
brightone profile image
Oleksii Filonenko

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

Collapse
citizen428 profile image
Michael Kohl

F#:

module DailyChallenge

open System.Text.RegularExpressions

let nextHappyYear year = 
    Seq.initInfinite (fun index -> year + index + 1)
    |> Seq.find (fun n -> not(Regex.Match(string n, "(\d).*\1").Success))

Tests:

module DailyChallengeTest

open FsUnit.Xunit
open Xunit
open DailyChallenge

[<Fact>]
let ``should return 7801 when passing 7712``() = 
    nextHappyYear 7712 |> should equal 7801

[<Fact>]
let ``should return 1023 when pasasing 1001``() = 
    nextHappyYear 1001 |> should equal 1023

[<Fact>]
let ``should return 2019 when pasasing 2018``() = 
    nextHappyYear 2018 |> should equal 2019

I also made an alternative version for people who don't like regular expressions:

let nextHappyYear year =
    Seq.initInfinite (fun index -> year + index + 1)
    |> Seq.find (fun n ->
           n
           |> string
           |> Seq.countBy id
           |> Seq.forall (fun (_, count) -> count = 1))
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
khalyomede profile image
Khalyomede

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
mbaas2 profile image
Michael Baas

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

And a PHP solution:

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

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
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
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)