DEV Community

Myoungjin Jeon
Myoungjin Jeon

Posted on • Updated on

Weekly Challenge #080 Task #1 :: Raku

Here we go~ another Weekly Challenge #080

TASK #1 Smallest Positive Number Bits

Submitted by: Mohammad S Anwar

You are given unsorted list of integers @N.

Write a script to find out the smallest positive number missing.
Example 1:

Input: @N = (5, 2, -2, 0)
Output: 1

Example 2:

Input: @N = (1, 8, -1)
Output: 2

Example 3:

Input: @N = (2, 0, -1)
Output: 1

I'm not a golf style programmer but Perl and Raku are very good ones for golfed programming.
( golf in programming is written as short as possible in length, no need to efficient, if the code fulfil the output what the task request. )
I felt something golfed edge of task #1, and I wanted to give a try with Raku.

there are some ways to get the input. input from STDIN is usual way to get user data, however Perl Weekly Challenge is not strict about how we get the data from.

So I decided to get the list of the integer from command line's argument. and if we write function named "MAIN", the subroutine will take care of argument list very nicely. this is where Raku shines because Raku provides pretty good class system and type checking on argument is very easy and the user can concentrate on the task itself.

 sub MAIN( *@args where @args.all ~~ Int ) {                                       
     @args.elems.say;                                                              
     @args.List.say;                                                               
 }             
raku test.raku 5 2 -2 0 # example #1
4
(5 2 -2 0)

if we give some string value in the arguments it will kindly remind you the usage. simple. nice. but .. wait! this golf so we won't check the details on arguments, let's trust user input. and I'm going to use an ancient variable @_ which is automatically has the an series of values in a Array form.

sub MAIN {  @_.say; }
raku test.raku 5 2 -2 0 # example #1
[5 2 -2 0]

we might catch the difference between (5 2 -2 0) and [5 2 -2 0]?
former one is a List latter one is Array. okay....
It doesn't really matter on this task because we only need to read the values from the List (or Array)

first thing we need to think about is how to sort the list.

sub MAIN { @_.sort.say; }

easy. then.. we might need to compare the two neighbouring numbers
and if the difference between them is more than 1.
Raku has a great built-in function called "rotor"

sub MAIN { @_.sort.rotor(2=>-1).say }
((-2 0) (0 2) (2 5))

ah... but we don't need any negative integer value...
(BTW zero is okay..)

sub MAIN { @_.sort.grep(*>=0).rotor(2=>-1).say }
((0 2) (2 5))

oki. comparision is done by using simple subtraction.

sub MAIN {
    @_.sort.
       rotor( 2=>-1 ).
       map( -> ($a, $b) { $b - $a } ).
       say;
}
(2 3)

But I realised that what if we have "3 4 5" ?
so I had to add "0" to the list(or array)... and also what if we have 1 2 3 and have to find 4?
Raku supports Inf for a virtual infinite value so I add it as well.
and maybe we need to unique routine on them??

sub MAIN {
    (|@_>>.Int,0,Inf).sort. # note "|" at the front of @_ will flatten the list. 
    unique.
    grep( * >= 0 ).
    rotor( 2 => -1 ).
    map( -> ($a, $b) { a => $b-$a } ).say;
}
(0 => 2 2 => 3 5 => Inf)

note: @_ takes actually not as Int but IntStr so I had to add >>.Int

okay.. now we find first case where the difference is more than 1 which is (0 => 2)
and we know the left value and just add "1" to it.
so the result of example #1 is "1"

the final solution form is different from what I wrote above.
but I decided to leave as it is. I reckon that it must be curious and interesting for someone.

and remember... this is golf. there is always a shorter way.

sub MAIN{say((|@_,0,Inf).sort.rotor(2=>-1).first({.[0]>-1>[-] $_})[0]+1)}

Discussion (1)

Collapse
jeongoon profile image
Myoungjin Jeon Author • Edited

Oh... what a day. I found totally new one.

[1..].first({@*ARGS.Set$_}).say;