Twice as Cute
with Raku

by Arne Sommer

Twice as Cute with Raku

[211] Published 20. November 2022.

This is my response to The Weekly Challenge #191.

Challenge #191.1: Twice Largest

You are given list of integers, @list.

Write a script to find out whether the largest item in the list is at least twice as large as each of the other items.

Example 1:
Input: @list = (1,2,3,4)
Output: -1

The largest in the given list is 4. However 4 is not greater than twice
of every remaining elements.
 1 x 2 <= 4
 2 x 2 <= 4
 2 x 3 >  4
Example 2:
Input: @list = (1,2,0,5)
Output: 1

The largest in the given list is 5. Also 5 is greater than twice of every
remaining elements.
 1 x 2 <= 5
 2 x 2 <= 5
 0 x 2 <= 5
Example 3:
Input: @list = (2,6,3,1)
Output: 1

The largest in the given list is 6. Also 6 is greater than twice of every
remaining elements.
 2 x 2 <= 6
 3 x 2 <= 6
 1 x 2 <= 6
Example 4:
Input: @list = (4,5,2,3)
Output: -1

The largest in the given list is 5. Also 5 is not greater than twice of
every remaining elements.
 4 x 2 >  5
 2 x 2 <= 5
 3 x 2 >  5

Off we go...

File: twice-largest
#! /usr/bin/env raku

unit sub MAIN (*@list where @list.elems > 0 && all(@list) ~~ Int,
  :v(:$verbose));

my @sorted  = @list.sort;                # [1]

say ":Sorted: @sorted[]" if $verbose;

my $largest = @sorted.pop;               # [2]
my $next    = @sorted.pop;               # [3]

say ":Largest: $largest" if $verbose;
say ":Next: $next" if $verbose;

say ($largest >= $next * 2) ?? 1 !! -1;  # [4]

[1] We are looking for the largest value. Using max will certainly do that, but we need the second largest value as well (and max cannot help us with this). So we sort the values instead. The default order is lowest first, which is fine.

[2] Get the largest value, by removing it from the end of the sorted list (with pop).

See docs.raku.org/routine/pop for more information about pop.

[3] Then we get the remaining highest value (again with pop. We do not have to compare every value, just this one. As «at least twice as large as each of the other items» will be satisfied if the largest of «the other items» work out.

[4] Then we simply compare the values, and print «1» if it passed the test, and «-1» otherwise.

Running it:

$ ./twice-largest 1 2 3 4
-1

$ ./twice-largest 1 2 0 5
1

$ ./twice-largest 2 6 3 1
1

$ ./twice-largest 4 5 2 3
-1

Looking good.

With verbose mode:

$ ./twice-largest -v 1 2 3 4
:Sorted: 1 2 3 4
:Largest: 4
:Next: 3
-1

$ ./twice-largest -v 1 2 0 5
:Sorted: 0 1 2 5
:Largest: 5
:Next: 2
1

$ ./twice-largest -v 2 6 3 1
:Sorted: 1 2 3 6
:Largest: 6
:Next: 3
1

$ ./twice-largest -v 4 5 2 3
:Sorted: 2 3 4 5
:Largest: 5
:Next: 4
-1

Challenge #191.2: Cute List

You are given an integer, 0 < $n <= 15.

Write a script to find the number of orderings of numbers that form a cute list.

With an input @list = (1, 2, 3, .. $n) for positive integer $n, an ordering of @list is cute if for every entry, indexed with a base of 1, either

1) $list[$i] is evenly divisible by $i
or
2) $i is evenly divisible by $list[$i]
Example:
Input: $n = 2
Ouput: 2

Since $n = 2, the list can be made up of two integers only i.e. 1 and 2.
Therefore we can have two list i.e. (1,2) and (2,1).

@list = (1,2) is cute since $list[1] = 1 is divisible by 1 and $list[2]
  = 2 is divisible by 2.
File: cute-list
#! /usr/bin/env raku

unit sub MAIN (UInt $n where 0 < $n <= 15, :v(:$verbose));     # [1]

my @list = (1 .. $n);                                          # [2]

say ":List: [{ @list.join(",") }]" if $verbose;

my @permutations = @list.permutations;                         # [3]

say ":Permutations: ", @permutations if $verbose;

my $cute;

for @permutations -> @permutation                              # [4]
{
  $cute++ if is-cute(@permutation);                            # [5]
}

say $cute;                                                     # [6]

sub is-cute (@list)                                            # [7]
{
  for 1 .. @list.elems -> $i                                   # [8]
  {
    return 0 unless @list[$i -1] %% $i || $i %% @list[$i -1];  # [9]
  }

  return 1;                                                    # [10]
}

[1] Note the stacked comparison in the where clause. The UInt (unsigned integer) type can be replaced with the more known Int here without causing problems.

[2] Generate the list.

[3] Get all the permutations, with the aptly named permutations method.

See docs.raku.org/routine/permutations for more information about permutations.

[4] Iterate over the permutations,

[5] Add one to the counter if the current permutution is cute.

[6] Print the result.

[7] Is the list cute?

[8] Iterate over the indices (1 based).

[9] We fail (return 0) if both divisible expressions fail.

[10] If we reach the end of the loop without failing, we have succeeded.

Running it:

$ ./cute-list 2
2

We got the expected result, but this is the only example we got.

Let us try some other values, with verbose mode:

$ ./cute-list -v 1
:List: [1]
:Permutations: [(1)]
1

$ ./cute-list -v 2
:List: [1,2]
:Permutations: [(1 2) (2 1)]
2

$ ./cute-list -v 3
:List: [1,2,3]
:Permutations: [(1 2 3) (1 3 2) (2 1 3) (2 3 1) (3 1 2) (3 2 1)]
3

$ ./cute-list -v 4
:List: [1,2,3,4]
:Permutations: [(1 2 3 4) (1 2 4 3) (1 3 2 4) (1 3 4 2) (1 4 2 3) ...]
8

$ ./cute-list -v 5
:List: [1,2,3,4,5]
:Permutations: [(1 2 3 4 5) (1 2 3 5 4) (1 2 4 3 5) (1 2 4 5 3) ...]
10

$ ./cute-list -v 6
:List: [1,2,3,4,5,6]
:Permutations: [(1 2 3 4 5 6) (1 2 3 4 6 5) (1 2 3 5 4 6) ...]
36

$ ./cute-list -v 7
:List: [1,2,3,4,5,6,7]
:Permutations: [(1 2 3 4 5 6 7) (1 2 3 4 5 7 6) (1 2 3 4 6 5 7) ...]
41

$ ./cute-list -v 8
:List: [1,2,3,4,5,6,7,8]
:Permutations: [(1 2 3 4 5 6 7 8) (1 2 3 4 5 6 8 7) (1 2 3 4 5 7 6 8) ...]
132

$ ./cute-list -v 9
:List: [1,2,3,4,5,6,7,8,9]
:Permutations: [(1 2 3 4 5 6 7 8 9) (1 2 3 4 5 6 7 9 8) ...]
250

$ ./cute-list -v 10
:List: [1,2,3,4,5,6,7,8,9,10]
:Permutations: [(1 2 3 4 5 6 7 8 9 10) (1 2 3 4 5 6 7 8 10 9) ...]
700

$ time ./cute-list -v 11
:List: [1,2,3,4,5,6,7,8,9,10,11]
:Permutations: [(1 2 3 4 5 6 7 8 9 10 11) (1 2 3 4 5 6 7 8 9 11 10)
750

Higher values gives longer runtime. «10» took 21 seconds on my pc, whereas «11» took 9 minutes. I stopped there...

Note that I have shortened the permutations-lines, to make the output readable. Raku will also shorten them (courtesy of say), but not so agressively.

And that's it.