This is my response to The Weekly Challenge #277.
@words1
and @words2
.
Input: @words1 = ("Perl", "is", "my", "friend")
@words2 = ("Perl", "and", "Raku", "are", "friend")
Output: 2
The words "Perl" and "friend" appear once in each array.
Example 2:
Input: @words1 = ("Perl", "and", "Python", "are", "very", "similar")
@words2 = ("Python", "is", "top", "in", "guest", "languages")
Output: 1
Example 3:
Input: @words1 = ("Perl", "is", "imperative", "Lisp", "is", "functional")
@words2 = ("Crystal", "is", "similar", "to", "Ruby")
Output: 0
File: count-common
#! /usr/bin/env raku
unit sub MAIN ($sentence1, $sentence2, :v(:$verbose)); # [1]
my @words1 = $sentence1.words; # [2]
my @words2 = $sentence2.words; # [2a]
my $once1 = (@words1.Bag.grep: *.value == 1).Bag; # [3]
my $once2 = (@words2.Bag.grep: *.value == 1).Bag; # [3a]
my $common = $once1 (&) $once2; # [4]
if $verbose
{
say ": Once1: { $once1.keys.sort.join(", ") }";
say ": Once2: { $once2.keys.sort.join(", ") }";
say ": Common: { $common.keys.sort.join(", ") }";
}
say $common.elems; # [5]
[1] Two sentences, without any restrictions on length or content.
[2] Turn the sentences into arrays of words.
[3] Coerce the array into a Bag
, a hash like structure
that counts the frequency, and keep only those that appear once. Ensure
that the result is also a Bag.
See docs.raku.org/routine/Bag for more information about Bag
.
[4] Get the intersection of the two Bags, with the (&)
operator.
See
docs.raku.org/routine/(&),%20infix%20%E2%88%A9
for more information about the intersection operator (&)
.
[5] Print the number of elements in the Bag.
Running it:
$ ./count-common "Perl is my friend" "Perl and Raku are friend"
2
$ ./count-common "Perl and Python are very similar" \
"Python is top in guest langages"
1
$ ./count-common "Perl is imperative Lisp is functional" "\
Crystal is similar to Ruby"
0
Looking good.
With verbose mode:
$ ./count-common -v "Perl is my friend" "Perl and Raku are friend"
: Once1: Perl, friend, is, my
: Once2: Perl, Raku, and, are, friend
: Common: Perl, friend
2
$ ./count-common -v "Perl and Python are very similar" \
"Python is top in guest langages"
: Once1: Perl, Python, and, are, similar, very
: Once2: Python, guest, in, is, langages, top
: Common: Python
1
$ ./count-common -v "Perl is imperative Lisp is functional" \
"Crystal is similar to Ruby"
: Once1: Lisp, Perl, functional, imperative
: Once2: Crystal, Ruby, is, similar, to
: Common:
0
@ints
.
0 < |x - y| < min(x, y)
.
Input: @ints = (1, 2, 3, 4, 5)
Ouput: 4
Strong Pairs: (2, 3), (3, 4), (3, 5), (4, 5)
Example 2:
Input: @ints = (5, 7, 1, 7)
Ouput: 1
Strong Pairs: (5, 7)
We can deduce quite a lot about the input from the given rule:
x
and y
must be distinct, as 0 < |x - y|
would give 0 < 0
if they were equal
x
and y
must be positive (and greater than zero),
as 0 < min(x, y)
will only hold if the lowest value is 1
(2,3)
but not (3,2)
,
so the pairs are Sets (without order). That means that we can
use combinations
#! /usr/bin/env raku
subset PosInt of Int where * > 0;
unit sub MAIN (*@ints where all(@ints) ~~ PosInt && @ints.elems > 1, # [1]
:v(:$verbose));
my @unique = @ints.unique; # [2]
my $count = 0; # [3]
for @unique.combinations(2) -> ($left, $right) # [4]
{
my $is-strong = 0 < abs($left - $right) < min($left, $right); # [5]
say ": Pair ($left, $right) { $is-strong ?? "strong" !! "-" }" if $verbose;
$count++ if $is-strong; # [6]
}
say $count; # [7]
[1] Ensure at least two elements, all of which must be of the UInt
type (Unsigned Integer). Note that this does not prevent zeroes in the
input.
[2] Get rid of duplicates, as they only lead to extra work.
[3] The result will end up here.
[4] Iterate over all the combinations of two values.
See docs.raku.org/routine/combinations for more information about combinations
.
[5] Do the two values satisfy the given rule?
[6] If so, increase the count.
[7] Print the count.
Running it:
$ ./strong-pair 1 2 3 4 5
4
$ ./strong-pair 5 7 1 7
1
Looking good.
With verbose mode:
$ ./strong-pair -v 1 2 3 4 5
: Pair (1, 2) -
: Pair (1, 3) -
: Pair (1, 4) -
: Pair (1, 5) -
: Pair (2, 3) strong
: Pair (2, 4) -
: Pair (2, 5) -
: Pair (3, 4) strong
: Pair (3, 5) strong
: Pair (4, 5) strong
4
$ ./strong-pair -v 5 7 1 7
: Pair (5, 7) strong
: Pair (5, 1) -
: Pair (7, 1) -
1
And that's it.