Perl Weekly Challenge: Reverse Vowels by the Power of Three

This week’s musical theme: Power of Two by the Indigo Girls. Listen to the song one-and-a-half times and you’ll have the power of three, right?

Onward to Perl Weekly Challenge 254!

Task 1: Three Power

You are given a positive integer, $n.

Write a script to return true if the given integer is a power of three otherwise return false.

Example 1

Input: $n = 27
Output: true

27 = 3 ^ 3

Example 2

Input: $n = 0
Output: true

0 = 0 ^ 3

Example 3

Input: $n = 6
Output: false

Approach

Was it really three weeks ago that I last used recursion? Huh. Anyway, I’m going to have a function that takes two parameters, $n and a number to raise to the power of three, $pow. Initially, I call it with $pow = 0. If $n == $pow ^ 3, we return true. If $n < $pow ^ 3, we return false (because the number is larger than the last power of three, but smaller than this one). Otherwise, we return the value returned by calling the function again with $pow + 1. Eventually, we’ll match one of the first two conditions and return either true or false.

Raku

By using a default value for the second parameter, I can call isAPowerOfThree($n) to begin with, and let the recursive calls pass the numbers that get raised to the power of three.

sub isAPowerOfThree($n, $pow = 0) {
  if ($n == $pow ** 3) {
    return 'true';
  }
  elsif ($n < $pow ** 3) {
    return 'false';
  }
  return isAPowerOfThree($n, $pow + 1);
}

View the entire Raku script for this task on GitHub.

Perl

Since Perl’s function signatures (the default since Perl 5.36) allow for default values the same way Raku does, we don’t have to change anything except the string concatenation operator in my solution() function (shown in the full solution). But if I wanted to be compatible back to Perl 5.10, I could write it this way.

sub isAPowerOfThree {
  my $n   = shift;
  my $pow = shift() // 0;

  if ($n == $pow ** 3) {
    return 'true';
  }
  elsif ($n < $pow ** 3) {
    return 'false';
  }
  return isAPowerOfThree($n, $pow + 1);
}

View the entire Perl script for this task on GitHub.

Python

For Python, I didn’t have to adjust the logic at all, only the syntax.

def isAPowerOfThree(n, pow = 0):
    if n == pow ** 3:
        return 'true'
    elif n < pow ** 3:
        return 'false'
    return isAPowerOfThree(n, pow + 1)

View the entire Python script for this task on GitHub.


Task 2: Reverse Vowels

You are given a string, $s.

Write a script to reverse all the vowels (a, e, i, o, u) in the given string.

Example 1

Input: $s = "Raku"
Output: "Ruka"

Example 2

Input: $s = "Perl"
Output: "Perl"

Example 3

Input: $s = "Julia"
Output: "Jaliu"

Example 4

Input: $s = "Uiua"
Output: "Auiu"

Approach

Ah, this one requires a bit more thought. We want to extract the vowels from the string into a list, but maintain the positions of the vowels in the string. We then reverse the list and put the vowels back into the string. One thing to note: the output string is title-cased.

Raku

I realized that I didn’t need to remove the vowels from the string, so I could use the vowels themselves as the placeholders.

sub reverseVowels($s) {
  # split string into letters
  my @letters = $s.split('', :skip-empty);

  # find the vowels
  my @vowels = @letters.grep({ /:i<[aeiou]>/ });

  # replace each vowel in reverse order, converting
  # any uppercase letters to lowercase
  for 0 .. @letters.end -> $i {
    if (@letters[$i] ~~ /:i<[aeiou]>/) {
      @letters[$i] = @vowels.pop.lc;
    }
  }

  # rejoin the array as a string, title casing it
  return tc(@letters.join(''));
}

View the entire Raku script for this task on GitHub.

Perl

sub reverseVowels($s) {
  # split string into letters
  my @letters = split(//, $s);

  # find the vowels
  my @vowels = grep { /[aeiou]/i } @letters;

  # replace each vowel in reverse order, converting
  # any uppercase letters to lowercase
  foreach my $i ( 0 .. $#letters) {
    if ($letters[$i] =~ /[aeiou]/i) {
      $letters[$i] = lc(pop @vowels);
    }
  }

  # rejoin the array as a string, title casing it
  return ucfirst(join('', @letters));
}

View the entire Perl script for this task on GitHub.

Python

import re

is_vowel = re.compile('[aeiou]', re.IGNORECASE)

def reverseVowels(s):
    # split string into letters
    letters = list(s)

    # find the vowels
    vowels = [ v for v in letters if is_vowel.match(v) ]

    # replace each vowel in reverse order, converting
    # any uppercase letters to lowercase
    for i in range(len(s)):
        if is_vowel.match(letters[i]):
            letters[i] = vowels.pop(-1)

    # rejoin the array as a string, title casing it
    return ''.join(letters).title()

View the entire Python script for this task on GitHub.


Here’s all my solutions in GItHub: https://github.com/packy/perlweeklychallenge-club/tree/master/challenge-254/packy-anderson