# Perl Weekly Challenge 116

Part 1 was probably the hardest this week, but I ended up being able to adapt a solution from an existing Python library.

You are given a number `\$N >= 10`.

Write a script to split the given number such that the difference between two consecutive numbers is always 1 and it shouldn’t have leading 0.

Print the given number if it’s impossible to split the number.

### Examples

``````Input: \$N = 1234
Output: 1,2,3,4

Input: \$N = 91011
Output: 9,10,11

Input: \$N = 10203
Output: 10203 as it is impossible to split satisfying the conditions.
``````

### Solution

See below for explanation and any implementation-specific comments.

``````# Raku adaptation of Python's more-itertools.partitions: https://git.io/JZL8Q
sub partitions(Str \$S) {
my @sequence = \$S.comb;
my \$n = @sequence.elems;
my @partitions = gather for (1..^\$n).combinations -> @combination {
my @partition = gather for (0, |@combination) Z (|@combination, \$n) -> (\$i, \$j) {
take [@sequence[\$i..^\$j]];
}
take @partition;
}
gather for @partitions -> @partition {
# Filter out elements with leading zeros
my @invalid = @partition.grep(*.head eq '0');
if @invalid.elems == 0 {
take @partition.map(*.join.Int);
}
}
}

sub challenge(Int \$N where \$N >= 10) returns Str {
my \$S = \$N.Str;
my \$solution = partitions(\$S).first: -> @partition {         # 
my @zipped = @partition[0..*-1] Z @partition[1..*];        # 
my @filtered = @zipped.grep(-> (\$a, \$b) { \$b - \$a == 1 }); # 
@zipped.elems > 0 && @zipped.elems == @filtered.elems;     # 
}

with \$solution { # 
\$solution.join(',');
} else {
\$S
}
}

sub MAIN(Int \$N) {
say challenge(\$N);
}
``````

This program runs as such:

``````\$ raku ch-1.raku 1234
1,2,3,4
``````

### Explanation

I won’t focus on the `partitions` function too much, as it is just a means to and end. At a high level, it takes a string (let’s say `1234`) and returns a list that looks like this: `((1234) (1 234) (12 34) (123 4) (1 2 34) (1 23 4) (12 3 4) (1 2 3 4))`; basically every permutation of every size split possible (with order maintained). Once we have that list of partitions, we want to find the first one that satisfies our condition – each element is 1 less than the next element. If we found one, return it as a comma-separated string. Otherwise, return the input.

1. `first` is kind of like `collectFirst` in Scala; it will return either the element that matches the condition or `Nil` if nothing matches.
2. To compare our elements pairwise, we need to zip them up like so. In Scala this could be `partition.init.zip(partition.tail)` or `partition.sliding(2)`, but again, Raku doesn’t have those cool functions.
3. Now that we have the zipped up, we filter it to down to elements that match our condition.
4. Finally, if `@filtered` didn’t remove anything, then this is a winner! We also need to check if `@zipped` is non-empty, because a `@partition` of size 1 will cause that.
5. `with` is the same as saying `if \$solution.defined`, since `\$solution` can be `Nil`.

## Task 2: Sum of Squares

You are given a number `\$N >= 10`.

Write a script to find out if the given number `\$N` is such that sum of squares of all digits is a perfect square. Print 1 if it is otherwise 0.

### Examples

``````Input: \$N = 34
Ouput: 1 as 3^2 + 4^2 => 9 + 16 => 25 => 5^2

Input: \$N = 50
Output: 1 as 5^2 + 0^2 => 25 + 0 => 25 => 5^2

Input: \$N = 52
Output: 0 as 5^2 + 2^2 => 25 + 4 => 29
``````

### Solution

See below for explanation and any implementation-specific comments.

``````sub challenge(Int \$N where \$N >= 10) returns Int {
my \$square-sum = \$N.comb.map(*²).sum;     # 
\$square-sum.sqrt.narrow ~~ Int ?? 1 !! 0; # 
}

sub MAIN(Int \$N) {
say challenge(\$N);
}
``````

This program runs as such:

``````\$ raku ch-2.raku 34
1
``````

### Explanation

We convert the input number to a list of digits, then square each digit, then sum all the squares. We then check if the sum of squares is an integer (i.e., a perfect square). If so, we return `1`, else `0`.

1. I like the first part support of Unicode in Raku. It makes it very clear we are squaring each element of a list.
2. I don’t like this – this takes 2 passes (one for squaring and one for summing). In Scala, I would write `list.foldLeft(0)((runningSum, elem) => runningSum + math.pow(elem, 2))`, which only takes one pass. However, the `math.pow` is uglier than it is in Raku, so you win some you lose some.
3. `narrow` returns the most granular numerical type that this number matches (`sqrt` returns a `Numeric`). If it is an `Int`, this is a perfect square.

## Final Thoughts

Two fun challenges this week! Glad I am ahead of the curve and won’t be behind due to a busy weekend this week.

Tags:

Categories:

Updated: