| 28 June 2026 | Challenge 379 |
There Is More Than One Way To Power
Task 1: Reverse String
Submitted by: Mohammad Sajid Anwar
You are given a string.
Write a script to reverse the given string without using standard reverse function.
Example 1
Input: $str = ""
Output: ""
Example 2
Input: $str = "reverse the given string"
Output: "gnirts nevig eht esrever"
Example 3
Input: $str = "Perl is Awesome"
Output: "emosewA si lreP"
Example 4
Input: $str = "v1.0.0-Beta!"
Output: "!ateB-0.0.1v"
Example 5
Input: $str = "racecar"
Output: "racecar"
Solution
I’ll regard reverse as the standard reverse function in Perl and “Reverse” |. as the standard primitive verb in J.
Any other way to reverse a string shall count as a valid solution to this task.
There is quite a number of approaches:
- convert the string to an array and use pop/push or shift/unshift to produce a reversed copy
- perform similar actions directly on the string
- use indices counting from the end of the string to pick the reversed string
- use a special syntax to pick a reversed dimension from an array
- etc.
Perl
Some variants:
use strict;
use warnings;
use experimental 'signatures';
use List::Gather;
use PDL;
use PDL::Char;
use PDL::NiceSlice;
sub reverse_slice ($str) {
join '', (split //, $str)[map -$_, 1 .. length $str];
}
# gather/take instead of push
sub reverse_pop ($str) {
my @arr = split //, $str;
join '', gather {take pop @arr while @arr};
}
# like shift/unshift
sub reverse_substr ($str) {
my $rev = '';
substr($rev, 0, 0) = substr $str, 0, 1, '' while length $str;
$rev;
}
# avoid copying
sub reverse_inplace ($str) {
substr($str, 0, 0) = substr $str, $_, 1, '' for 1 .. length($str);
$str;
}
# natively fails on an empty string
sub reverse_pdl ($str) {
length($str) ? PDL::Char->new($str)->(-1:0)->atstr(0) : '';
}
See the full solution to task 1.
J
rev_from is almost identical to reverse_slice: pick negative indices that count from the end of the string.
In rev_substr, the substring is taken from the start to the end in reverse order __.
rev_from =: {~ -@>:@i.@# : [:
rev_substr =: __&(];.0)
Task 2: Armstrong Number
Submitted by: Mohammad Sajid Anwar
You are given two integers, $base and $limit.
Write a script to find all Armstrong numbers in base $base that are less than $limit.
If raising each of the digits of a nonnegative integer to the power of the total number of digits, then taking the sum, equals the original number, it is an Armstrong number.
Example 1
Input: $base = 10, $limit = 1000
Output: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407)
Example 2
Input: $base = 7, $limit = 1000
Output: (0, 1, 2, 3, 4, 5, 6, 10, 25, 32, 45, 133, 134, 152, 250)
Example 3
Input: $base = 16, $limit = 1000
Output: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 342, 371, 520, 584, 645)
Solution
Following a brute-force approach:
Calculate the digit power sum in base B for all numbers from zero to the limit and pick those where it equals the number itself.
Perl
Using a lexical sub to calculate the digit power sum.
use v5.26;
use warnings;
use experimental 'signatures';
use Math::Prime::Util qw(todigits vecsum);
sub armstrong ($base, $limit) {
my sub dps {
my @digits = todigits shift, $base;
vecsum map $_ ** @digits, @digits;
}
grep $_ == dps($_), 0 .. $limit;
}
See the full solution to task 2.
J
The same in J with one minor difference: dps is not called as a verb but resolved to its value when a verb is created as m armstrong.
armstrong =: adverb define
dps =. ([: +/ ] ^ #) @ (m&#.inv)
((] #~ ] = dps"0) @: i. @ >:) f. : [:
)
10 armstrong
(] #~ ] = ([: +/ ] ^ #)@(10&#.^:_1)"0)@:i.@>: :[:
10 armstrong 1000
0 1 2 3 4 5 6 7 8 9 153 370 371 407