The Bear's Den

Enter at your own risk

Average Strings

Task 1: Divisible Average

Submitted by: Mohammad Sajid Anwar


You are given an array of positive integers.

Write a script to return the closest integer to the mean value of all even integers that are divisible by 3. If none is divisible, return 0.

Example 1

Input: @arr = (18, 5, 7, 11)
Output: 18

18 is the only even number and divisible by 3.
Average: 18 / 1 = 18.

Example 2

Input: @arr = (6, 12, 18, 24, 30, 40)
Output: 18

The qualifying numbers are 6, 12, 18, 24, and 30.
Average: (6 + 12 + 18 + 24 + 30) / 5 = 90 / 5 = 18

Example 3

Input: @arr = (3, 9, 15, 21, 27)
Output: 0

None of the elements are even.
Since no elements qualify, return 0.

Example 4

Input: @arr = (6, 12, 14, 20)
Output: 9

The qualifying numbers are 6 and 12.
Average: (6 + 12) / 2 = 9.

Example 5

Input: @arr = (6, 6, 6, 12, 12)
Output: 8

All five numbers are even and divisible by 3.
Average: (6 + 6 + 6 + 12 + 12) / 5 = 8.4 => 8

Solution

There are three simple steps to be performed:

Perl

avg produces nan for empty lists, which can to be transformed into 0 with an intermediate step:

use strict;
use warnings;
use PDL;

sub divisible_avg {
    my $l = pdl @_;

    ($l->where(!($l % 6))->avg->setnantobad->setbadtoval(0) + .5)->floor;
}

See the full solution to task 1.

J

It’a bit simpler in J as the average over an empty list produces 0.

avg_m6 =: _(adverb define)
  m6 =. ] #~ -. @ * @ (6&|)
  avg =. +/ % #
  round =. <. @ (0.5&+)
  (round @ avg @ m6) f. : [:
)

See the full solution.

Task 2: String Difference

Submitted by: Mohammad Sajid Anwar


You are given an array of equal length strings.

Write a script to find the difference integer array of each word in the given array. There will be one word with a different array; return that word.

Each words[i] can be converted into a difference integer array difference[i] of length n - 1 where difference[i][j] = words[i][j+1] - words[i][j]

Example 1

Input: @words = ("ab", "bc", "cd", "zy")
Output: "zy"

"ab" => [1 - 0] = [1]
"bc" => [2 - 1] = [1]
"cd" => [3 - 2] = [1]
"zy" => [24 - 25] = [-1]

Example 2

Input: @words = ("cba", "fed", "azy")
Output: "azy"

"cba" => [1 - 2, 0 - 1] = [-1, -1]
"fed" => [4 - 5, 3 - 4] = [-1, -1]
"azy" => [25 - 0, 24 - 25] = [25, -1]

Example 3

Input: @words = ("pop", "ada", "beb", "cfc")
Output: "pop"

"pop" => [14 - 15, 15 - 14] = [-1, 1]
"ada" => [3 - 0, 0 - 3] = [3, -3]
"beb" => [4 - 1, 1 - 4] = [3, -3]
"cfc" => [5 - 2, 2 - 5] = [3, -3]

Example 4

Input: @words = ("aaaa", "zzzz", "mmmm", "aaba")
Output: "aaba"

"aaaa" => [0 - 0, 0 - 0, 0 - 0] = [0, 0, 0]
"zzzz" => [25 - 25, 25 - 25, 25 - 25] = [0, 0, 0]
"mmmm" => [12 - 12, 12 - 12, 12 - 12] = [0, 0, 0]
"aaba" => [0 - 0, 1 - 0, 0 - 1] = [0, 1, -1]

Example 5

Input: @words = ("aceg", "bdfh", "cegi", "azbz")
Output: "azbz"

"aceg" => [2 - 0, 4 - 2, 6 - 4] = [2, 2, 2]
"bdfh" => [3 - 1, 5 - 3, 7 - 5] = [2, 2, 2]
"cegi" => [4 - 2, 6 - 4, 8 - 6] = [2, 2, 2]
"azbz" => [25 - 0, 1 - 25, 25 - 1] = [25, -24, 24]

Solution

Group the words by string difference and select the group(s) having a single element.

It is not specified how to handle multiple instances of words having a unique string difference. For the sake of convenience, selecting all of them.

Perl

Convert the string difference vector into a string by joining its elements with colons.

use strict;
use warnings;

use List::MoreUtils 'slide';
use List::UtilsBy 'partition_by';
use List::Util 'pairvalues';

sub single_str_diff {
    state sub str_diff {
        join ':', slide {$b - $a} map ord, split //, shift;
    };

    map @$_ == 1 ? @$_ : (), pairvalues partition_by \&str_diff, @_;
}

See the full solution to task 2.

J

Very similar to the Perl solution. Uses true vectors from str_diff to partition the words.

single_str_diff =: _(adverb define)
  str_diff =. 2&(-/\) @ (a.&i.) @ >
  box_by =. </.
  select_single =. ] #~ 1 = #@>
  (; @ select_single @ (str_diff box_by ])) f. : [:
)

See the full solution.