diff options
| -rwxr-xr-x | challenge-132/mattneleigh/perl/ch-1.pl | 163 | ||||
| -rwxr-xr-x | challenge-132/mattneleigh/perl/ch-2.pl | 134 |
2 files changed, 297 insertions, 0 deletions
diff --git a/challenge-132/mattneleigh/perl/ch-1.pl b/challenge-132/mattneleigh/perl/ch-1.pl new file mode 100755 index 0000000000..647916d4d2 --- /dev/null +++ b/challenge-132/mattneleigh/perl/ch-1.pl @@ -0,0 +1,163 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Time::Local; + +################################################################################ +# Begin main execution +################################################################################ + +my @birthday_dates = ( + "2021/09/18", + "1975/10/10", + "1967/02/14" +); +my $birthday_date; +my $reference_date = "2021/09/22"; + +foreach $birthday_date (@birthday_dates){ + print("Input: $birthday_date\n"); + print(" With reference date $reference_date:\n"); + printf( + " Output: %s\n", + join( + ", ", + birthday_mirror($birthday_date, $reference_date) + ) + ); + print(" With current date:\n"); + printf( + " Output: %s\n\n", + join( + ", ", + birthday_mirror($birthday_date) + ) + ); +} + +exit(0); +################################################################################ +# End main execution; subroutines follow +################################################################################ + + + +################################################################################ +# Given a birthdate and an optional reference date, calculate the mirror dates +# for same- the date before the birthdate and after the reference date that +# correspond to the length of the time interval between the two dates. If no +# reference date is specified, the current date will be used. +# Takes two arguments: +# * A string defining a birthdate, consisting solely of the date itself in the +# format YYYY/MM/DD +# * An optional string defining a reference date, subject to the same format +# requirements as the birthdate; if this argument is omitted, the current +# date, according to the local system clock, will be used +# Returns: +# * A list with the following members: +# - A string containing the date BEFORE the birth date corresponding to the +# length of time elapsed between the birth date and the reference date +# - A string containing the date AFTER the reference date corresponding to +# the length of time elapsed between the birth date and the reference date; +# as noted above, if no reference date is specified, the current date will +# be used +# NOTE: This function requires that the system correctly handle negative time +# values with respect to the start of the UNIX epoch; this is not mandated by +# the POSIX standard, but in practice most modern systems support this +################################################################################ +sub birthday_mirror{ + my $birthday = shift(); + my $reference_date = shift(); + + my @time_values; + my $delta; + + # Calculate the epoch time at 12:00:00 on + # the specified birthdate; noon is used + # instead of midnight so leap seconds + # won't push the time into the wrong day- + # for reasonable human lifespans, + # anyway... + $birthday = noon_on_date($birthday); + + # Calculate the epoch time at 12:00:00 + # on the reference date + if(defined($reference_date)){ + $reference_date = noon_on_date($reference_date); + } else{ + # No reference date defined; use the + # current date, making sure to pull the + # time from the system clock only once + $reference_date = time(); + @time_values = localtime($reference_date); + $reference_date -= ( + ($time_values[2] - 12) * 3600 + + + $time_values[1] * 60 + + + $time_values[0] + ); + } + + # Difference (delta) between the + # reference date and the birth date + $delta = $reference_date - $birthday; + + # Subtract the delta from the birth date + @time_values = localtime($birthday - $delta); + $birthday = sprintf( + "%4d/%02d/%02d", + $time_values[5] + 1900, + $time_values[4] + 1, + $time_values[3] + ); + + # Add the delta to the reference date + @time_values = localtime($reference_date + $delta); + $reference_date = sprintf( + "%4d/%02d/%02d", + $time_values[5] + 1900, + $time_values[4] + 1, + $time_values[3] + ); + + return($birthday, $reference_date); + +} + + + +################################################################################ +# Calculate the UNIX epoch time in seconds at noon (12:00:00 local system time) +# on a specified date +# Takes one argument: +# * A string defining a date, consisting solely of the date itself in the +# format YYYY/MM/DD +# Returns: +# * The number of seconds from the start of the UNIX epoch to noon on the +# specified date, in local system time; if this time is before the start of +# the epoch, the value returned will be negative +# NOTE: This function requires that the system correctly handle negative time +# values with respect to the start of the UNIX epoch; this is not mandated by +# the POSIX standard, but in practice most modern systems support this +################################################################################ +sub noon_on_date{ + my $date = shift(); + + my @time_values; + + @time_values = ($date =~ m/^(\d{4})\/(\d{2})\/(\d{2})$/); + + # timelocal() is from Time::Local + return( + timelocal( + 0, 0, 12, $time_values[2], $time_values[1] - 1, $time_values[0] + ) + ); + +} + + + diff --git a/challenge-132/mattneleigh/perl/ch-2.pl b/challenge-132/mattneleigh/perl/ch-2.pl new file mode 100755 index 0000000000..b3764565c7 --- /dev/null +++ b/challenge-132/mattneleigh/perl/ch-2.pl @@ -0,0 +1,134 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use English; + +################################################################################ +# Begin main execution +################################################################################ + +my @player_ages = ( + [20, "Alex" ], + [28, "Joe" ], + [38, "Mike" ], + [18, "Alex" ], + [25, "David" ], + [18, "Simon" ] +); +my @player_names = ( + ["Alex", "Stewart"], + ["Joe", "Root" ], + ["Mike", "Gatting"], + ["Joe", "Blog" ], + ["Alex", "Jones" ], + ["Simon","Duane" ] +); +my $row; + +print("\nMerged rows:\n"); +foreach $row (@{hash_join(\@player_ages, 1, \@player_names, 0)}){ + print_table_row($row); +} +print("\n"); + +exit(0); +################################################################################ +# End main execution; subroutines follow +################################################################################ + + + +################################################################################ +# Perform a hash join of two lists of table rows, based on the specified key +# fields. The original arrays will NOT be modified. The order of rows in the +# merged list will depend on the order of rows with matching keys in the Build +# and Probe lists. +# Takes four arguments: +# * A ref to a list of table rows; this will be treated as the Build List +# * The index of the field to use as the key from the Build List +# * A ref to a list of table rows; this will be treated as the Probe List +# * The index of the field to use as the key from the Probe List +# Returns: +# * A ref to a list of merged table rows +# Adapted from the algorithm described at: +# http://www.dcs.ed.ac.uk/home/tz/phd/thesis/node21.htm +################################################################################ +sub hash_join{ + my $build = shift(); + my $build_index = shift(); + my $probe = shift(); + my $probe_index = shift(); + + my $row; + my $key; + my %table = (); + my $joined = []; + + # Build phase- build a table of things + # from the build rows, using the specified + # field as the key; make each entry in the + # table a list of rows, in case more than + # one thing matches the key + foreach $row (@{$build}){ + # Copy the row from the build list, then + # remove the key from the row before + # adding to that key's list in the table + $row = [ @{$row} ]; + $key = splice(@{$row}, $build_index, 1); + push(@{$table{$key}}, $row); + } + + # Probe phase- loop over the probe list, + # examining the table for occurances of the + # specified key... + foreach $row (@{$probe}){ + $key = $row->[$probe_index]; + + if($table{$key}){ + # The key from this row appears in the build + # table- copy the row and delete the key + $row = [ @{$row} ]; + splice(@{$row}, $probe_index, 1); + + # Loop over everything in the table for this + # key and merge the built row with the probe + # row, storing the combination in the joined + # list + foreach my $built_row (@{$table{$key}}){ + push(@{$joined}, [ @{$built_row}, $key, @{$row} ]); + } + } + } + + return($joined); + +} + + + +################################################################################ +# Print the contents of a table row to STDOUT +# Takes one argument: +# * A ref to the row to print out, which must be an array of values that will +# be interpreted as strings +# Returns no meaningful value +################################################################################ +sub print_table_row{ + + printf( + "%s\n", + join( + " ", + map( + { sprintf("%8s", $_); } + @{$ARG[0]} + ) + ) + ); + +} + + + |
