Perl Weekly Challenge #233 - Similar Words and Frequency Sort

Hello everybody! For this week's weekly challenge I thought the challenges looked really easy, but they both had a couple slight complicating factors. Also, this was the first time I've used sub signatures.

Similar Words

For this one, we're looking for words that share all characters. We print out each pair of countries.

#!/usr/bin/perl
use v5.36;

my @words = @ARGV;
my $matched = 0;
for (my $i = 0; $i <= $#ARGV - 1; $i++) {
    my $start_word = $words[$i];
    my %start_chars = map {$_ => 1} split(//, $start_word);

    for (my $j = $i + 1; $j <= $#ARGV; $j++) {
        my $match_word = $words[$j];
        my %match_chars = map {$_ => 1} split(//, $match_word);

        if (hashes_equal(\%start_chars, \%match_chars)) {
            say $start_word . ", " . $match_word;
            $matched = 1;
        }
    }
}
say 0 unless $matched;

sub hashes_equal ($start_ref, $match_ref) {
    my %start_chars = %{$start_ref};
    my %match_chars = %{$match_ref};

    if (scalar keys %start_chars == scalar keys %match_chars) {
        foreach (keys %start_chars) {
            if (!defined($match_chars{$_})) {
                return;
            }
        }
        return 1;
    } else {
        return;
    }
}

It essentially boils down to looping through all combinations of words in two loops, converting each word to a hash containing all unique characters. hashes_equal makes sure that the hashes have the same number of keys, then tries the keys and makes sure they have the same values.

Frequency Sort

For this one, we're sorting numbers by how frequently they occur, in increasing order, except when they share a frequency, then we sort them decreasing by value.

Here's the code:

#!/usr/bin/perl
use v5.36;

my %ints;
$ints{$_}++ foreach @ARGV;

my %ints_by_occurrence;
my @results;

foreach (keys %ints) {
    push @{$ints_by_occurrence{$ints{$_}}}, $_;
}
foreach (sort keys %ints_by_occurrence) {
    my $frequency = $_;
    foreach (sort {$b <=> $a} @{$ints_by_occurrence{$frequency}}) {
        my $number = $_;
        for (1..$frequency) {
            push @results, $number;
        }
    }
}
say $_ foreach @results;

This time we're making a hash of arrays, where %intsbyoccurrence uses frequencies as the key, and an array of numbers as the value. %ints contains the initial histogram which is reversed into %intsbyoccurrence. We sort once by frequency, then we sort each array of a given frequency by value, which is pushed onto the results array in the proper order.

Those are my solutions to this week's challenge! Hopefully I'll have more for both challenges next week. See you then.

Leave a comment

About oldtechaa

user-pic Just getting back into Perl programming. I have a personal project, SeekMIDI, a small graphical MIDI sequencer.