Perl Weekly Challenge 181.

My solutions (task 1 and task 2 ) to the The Weekly Challenge - 181.

Task 1: Sentence Order

Submitted by: Mohammad S Anwar
You are given a paragraph.

Write a script to order each sentence alphanumerically and
print the whole paragraph.

Example
Input:

    All he could think about was how it would all end. There was
    still a bit of uncertainty in the equation, but the basics
    were there for anyone to see. No matter how much he tried to
    see the positive, it wasn't anywhere to be seen. The end was
    coming and it wasn't going to be pretty.

Ouput:
    about All all could end he how it think was would. a anyone
    basics bit but equation, for in of see still the the There
    there to uncertainty was were. anywhere be he how it matter
    much No positive, see seen the to to tried wasn't. and be
    coming end going it pretty The to was wasn't.

To solve the problem I read the whole file, separate into sentences by splitting on ‘.’, split on space, order alphanumerically and join, sticking in the end-of-sentence ‘.’. This fits comfortably into a oneliner.

perl -n -000 -E '
chomp; say ((join " ",  sort {fc $a cmp fc $b} split " ").". ") for split /\./;  say "";
' <<EOF |fmt
    All he could think about was how it would all end. There was
    still a bit of uncertainty in the equation, but the basics
    were there for anyone to see. No matter how much he tried to
    see the positive, it wasn't anywhere to be seen. The end was
    coming and it wasn't going to be pretty.

    It all started with the computer. Had he known what was to
    follow, he would have never logged on that day. But the truth
    was there was no way to know what was about to happen. So Dave
    pressed the start button, the computer booted up, the screen
    came alive, and everything Dave knew to be true no longer was.
EOF

(2nd paragraph taken from here). I used the -000 flag to split the input into paragraphs, so that I can arrange longer texts, and -n to implicitly loop over them. Each paragraph is split into sentences, reordered normalizing with the fc function before comparing strings, so that ‘Z’ doesn’t come before ‘a’. The results are:

about All all could end he how it think was would.  a anyone basics bit
but equation, for in of see still the the There there to uncertainty
was were.  anywhere be he how it matter much No positive, see seen the
to to tried wasn't.  and be coming end going it pretty The to was wasn't.

all computer It started the with.  day follow, Had have he he known
logged never on that to was what would.  about But happen know no the
there to to truth was was was way what.  alive, and be booted button,
came computer Dave Dave everything knew longer no pressed screen So
start the the the to true up, was.

The full code is

 1  # Perl weekly challenge 181
 2  # Task 1: Sentence order
 3  #
 4  # See https://wlmb.github.io/2022/09/05/PWC181/#task-1-sentence-order
 5  use v5.36;
 6  use Text::Wrap qw(wrap $columns $break);
 7  $columns=62; $break=qr/\s/;
 8  local $/ = ""; # paragraph mode
 9  while(<>){ # for each paragraph
10      chomp; # remove trailing newlines
11      my @output;
12      foreach(split /\./){ # For each sentence. Assume ends in "."
13  	my @words = split " "; # Separate into words. Assume a space even after punctuation.
14  	my @sorted_words = sort {fc $a cmp fc $b} @words;
15  	push @output, join(" ",  @sorted_words) . ". "; # join words and add ending "."
16      }
17      say wrap('', '', (join " ", @output), "\n");
18  }

Example:

./ch-1.pl <<EOF
    All he could think about was how it would all end. There was
    still a bit of uncertainty in the equation, but the basics
    were there for anyone to see. No matter how much he tried to
    see the positive, it wasn't anywhere to be seen. The end was
    coming and it wasn't going to be pretty.

    It all started with the computer. Had he known what was to
    follow, he would have never logged on that day. But the truth
    was there was no way to know what was about to happen. So Dave
    pressed the start button, the computer booted up, the screen
    came alive, and everything Dave knew to be true no longer was.
EOF

Results:

about All all could end he how it think was would.  a anyone
basics bit but equation, for in of see still the the There
there to uncertainty was were.	anywhere be he how it matter
much No positive, see seen the to to tried wasn't.  and be
coming end going it pretty The to was wasn't.

all computer It started the with.  day follow, Had have he he
known logged never on that to was what would.  about But
happen know no the there to to truth was was was way what.
alive, and be booted button, came computer Dave Dave
everything knew longer no pressed screen So start the the the
to true up, was.

Task 2: Hot Day

Submitted by: Mohammad S Anwar
You are given file with daily temperature record in random
order.

Write a script to find out days hotter than previous day.

Example
Input File: (temperature.txt)

2022-08-01, 20
2022-08-09, 10
2022-08-03, 19
2022-08-06, 24
2022-08-05, 22
2022-08-10, 28
2022-08-07, 20
2022-08-04, 18
2022-08-08, 21
2022-08-02, 25

Output:
2022-08-02
2022-08-05
2022-08-06
2022-08-08
2022-08-10

I can read the input into a hash, sort the keys and then compare temperatures. Assuming there are no holes in the table the problem may be solved with a 3-liner.

perl -MList::MoreUtils=pairwise -n -E '
BEGIN{sub dc($p, $q){@p=split "-",$p; @q=split "-",$q;@c=pairwise {$a<=>$b} @p,@q;
for(0..2){return $c[$_] if $c[$_]} 0}} chomp; ($d,$t)=split ", "; $t{$d}=$t;
END {@d=sort {dc($a, $b)} keys %t; for(1..@d-1){say $d[$_] if $t{$d[$_]}>$t{$d[$_-1]}}}
' <<EOF
2022-08-01, 20
2022-08-09, 10
2022-08-03, 19
2022-08-06, 24
2022-08-05, 22
2022-08-10, 28
2022-08-07, 20
2022-08-04, 18
2022-08-08, 21
2022-08-02, 25
EOF

Results:

2022-08-02
2022-08-05
2022-08-06
2022-08-08
2022-08-10

I test it with dates that cross month and year boundaries

perl -MList::MoreUtils=pairwise -n -E '
BEGIN{sub dc($p, $q){@p=split "-",$p; @q=split "-",$q;@c=pairwise {$a<=>$b} @p,@q;
for(0..2){return $c[$_] if $c[$_]} 0}} chomp; ($d,$t)=split ", "; $t{$d}=$t;
END {@d=sort {dc($a, $b)} keys %t; for(1..@d-1){say $d[$_] if $t{$d[$_]}>$t{$d[$_-1]}}}
' <<EOF
2022-12-31, 20
2023-01-08, 10
2023-01-02, 19
2023-01-05, 24
2023-01-04, 22
2023-01-09, 28
2023-01-06, 20
2023-01-03, 18
2023-01-07, 21
2023-01-01, 25
EOF

Results:

2023-01-01
2023-01-04
2023-01-05
2023-01-07
2023-01-09

For the full code I use the DateTime and Date::Parse modules to compare dates and add some checks for invalid and missing dates.

 1  # Perl weekly challenge 181
 2  # Task 2: Hot day
 3  #
 4  # See https://wlmb.github.io/2022/09/05/PWC181/#task-2-hot-day
 5  use v5.36;
 6  use List::MoreUtils qw(pairwise);
 7  use Date::Parse;
 8  use DateTime;
 9
10  my %temps;
11  while(<>){ # Input data from standard input in format YYYY-MM-DD, Temp
12      chomp;
13      my ($date, $temp)=split ", ";
14      $temps{$date}=$temp;
15  }
16  my %datetimes;
17  for(keys %temps){ # check valid dates
18      die "Wrong date $_" unless defined (my $time=str2time($_));
19      $datetimes{$_}=DateTime->from_epoch($time); # Build DateTime object
20  }
21  my @sorted=sort {DateTime->compare($datetimes{$a}, $datetimes{$b})} keys %temps;
22  for(1..@sorted-1){
23      die "Dates not consecutive"
24          unless $datetimes{$sorted[$_]}->delta_days($datetimes{$sorted[$_-1]})->days==1;
25      say $sorted[$_] if $temps{$sorted[$_]}>$temps{$sorted[$_-1]}
26  }
27
28
29

Example:

./ch-2.pl <<EOF
2022-08-01, 20
2022-08-09, 10
2022-08-03, 19
2022-08-06, 24
2022-08-05, 22
2022-08-10, 28
2022-08-07, 20
2022-08-04, 18
2022-08-08, 21
2022-08-02, 25
EOF

Results:

2022-08-02
2022-08-05
2022-08-06
2022-08-08
2022-08-10
Written on September 5, 2022