DEV Community

Discussion on: Daily Challenge #12 - Next Larger Number

Collapse
 
oscherler profile image
Olivier “Ölbaum” Scherler

I’m learning Erlang.

At first, I wanted to use digit swapping, like @coreyja , but it was harder than I initially thought (e.g. 351 needs two swaps, because the next larger number is 513, not 531.)

To validate the swapping method, I wrote a blunt version that converts a number into an array of digits, lists all the permutations, sorts them and finds the next occurence. For that I searched for a permutation function. It uses generators and list comprehensions, and I haven’t taken the time to understand it yet, but I’ll definitely try that in future challenges.

So my current solution is the blunt one (and I removed the unit tests for the intermediate functions, that are useful for development but not interesting for the solution).

-module( next ).

-include_lib("eunit/include/eunit.hrl").

% convert an integer to an array of digits
digits( N ) when N >= 0 ->
    digits( N, [] ).
digits( N, Digits ) when N < 10 ->
    [ N | Digits ];
digits( N, Digits ) ->
    digits( N div 10, [ N rem 10 | Digits ] ).

% convert an array of digits to an integer
number( Digits ) ->
    number( Digits, 0 ).
number( [ D | Rest ], N ) ->
    number( Rest, N * 10 + D );
number( [], N ) ->
    N.

% list all permutations of an array, taken from
% http://erlang.org/doc/programming_examples/list_comprehensions.html#permutations
perms( [] ) -> [ [] ];
perms( L )  -> [ [ H | T ] || H <- L, T <- perms( L -- [ H ] ) ].

% return the first element occuring after N in a list
find_next( N, [ N, M | _ ] ) ->
    M;
find_next( N, [ _ | Rest ] ) ->
    find_next( N, Rest );
find_next( _, [] ) ->
    none.

next( N ) ->
    Digits = digits( N ),
    Next = find_next( Digits, lists:sort( perms( digits( N ) ) ) ),
    case Next of
        none -> none;
        _ -> number( Next )
    end.

next_test_() -> [
    ?_assertEqual( none, next( 5 ) ),
    ?_assertEqual( 51, next( 15 ) ),
    ?_assertEqual( 536, next( 365 ) ),
    ?_assertEqual( 21, next( 12 ) ),
    ?_assertEqual( 531, next( 513 ) ),
    ?_assertEqual( 513, next( 351 ) ),
    ?_assertEqual( none, next( 531 ) ),
    ?_assertEqual( 2091, next( 2019 ) )
].