Perl Weekly Challenge 129.
My solutions (task 1, and task 2 ) to the The Weekly Challenge  129.
Task 1: Root Distance
Submitted by: Mohammad S Anwar
You are given a tree and a node of the given tree.
Write a script to find out the distance of the given node from
the root.
Example 1:
Tree:
1
/ \
2 3
\
4
/ \
5 6
Node: 6
Output: 3 as the distance of given node 6 from the root (1).
Node: 5
Output: 3
Node: 2
Output: 1
Node: 4
Output: 2
Example 2:
Tree:
1
/ \
2 3
/ \
4 5
\ /
6 7
/ \
8 9
Node: 7
Output: 3 as the distance of given node 6 from the root (1).
Node: 8
Output: 4
Node: 6
Output: 3
Trees are difficult to represent as ordinary text. In previous
challenges I have used perl code for nested array
references. They are easy to process but hard to write and
read for humans. Now, I will use nested emacs org mode
lists
to represent the tree. Thus, children are distinguished from
parents by their indentation. I allow valueless nodes to
represent empty trees. I make a routine to build the
internal tree structure, as a hash reference. As I read each
line, it is not known a priori if it corresponds to a
children, a sibling or an uncle. Thus, I may have to keep the
input line and it associated indentation and value until it is
ready for processing. After I build the tree structure, I
could use it to analyze the depth corresponding to each
value. Nevertheless, this could be done on the fly while
building the tree, after which the tree structure could be
discarded. Though I could have avoided building it, I kept it
for debugging.
# Perl weekly challenge 129
# Task 1: root distance
#
# See https://wlmb.github.io/2021/09/06/PWC129/#task1rootdistance
use warnings;
use strict;
use v5.12;
# use Data::Dumper;
my %root_distance; # hash of depths indexed by the node values.
# my $tree= # Throw away the actual tree, as it is not used
analyze_tree(1,1); # initialize indentation and depth.
# say Dumper($tree); # For debugging
say "Value: $_ Depth: ", $root_distance{$_}//"Not defined" for @ARGV;
sub analyze_tree {
my ($previous_indent, $depth)=@_;
++$depth;
my ($current_indent, $value)=analyze_line($previous_indent);
# If I found a node at the correct indentation, build a tree structure
$root_distance{$value}=$depth, #
return {value=>$value,
left=>analyze_tree($current_indent,$depth),
right=>analyze_tree($current_indent,$depth)}
if defined $current_indent && defined $value && $value ne '';
return undef;
}
sub analyze_line {
# Read and analyze lines. Keep them until their turn if outdented
state ($line, $current_indent, $value);
my $previous_indent=shift;
if(!defined $current_indent){
$line=<STDIN>;
return () if !defined $line  $line=~m/^\s*$/;
die "Malformed tree: $line" unless $line=~m/^(\s*)\s*(\d*)\s*$/;
$current_indent=length $1;
$value=$2;
}
if($current_indent>$previous_indent){
my $result_indent=$current_indent;
$current_indent=undef;
return ($result_indent, $value);
}
return ();
}
Example 1:
./ch1.pl 6 5 2 4 << 'EOF'
 1
 2
 3

 4
 5
 6
EOF
Results:
Value: 6 Depth: 3
Value: 5 Depth: 3
Value: 2 Depth: 1
Value: 4 Depth: 2
Example 2:
./ch1.pl 7 8 6 << 'EOF'
 1
 2
 4

 6
 8
 9

 3

 5
 7

EOF
Results:
Value: 7 Depth: 3
Value: 8 Depth: 4
Value: 6 Depth: 3
Task 2: Add Linked Lists
Submitted by: Mohammad S Anwar
You are given two linked list having single digit positive
numbers.
Write a script to add the two linked list and create a new
linked representing the sum of the two linked list
numbers. The two linked lists may or may not have the same
number of elements.
HINT: Just a suggestion, feel free to come up with your own
unique way to deal with the task. I am expecting a class
representing linked list. It should have methods to create a
linked list given list of single digit positive numbers and a
method to add new member. Also have a method that takes 2
linked list objects and returns a new linked list. Finally a
method to print the linked list object in a user friendly
format.
Example 1:
Input: L1 = 1 > 2 > 3
L2 = 3 > 2 > 1
Output: 4 > 4 > 4
Operation: Pick the first rightmost element of L1 i.e. 3
and adds to the first rightmost element of L2 i.e. 1. Finally
store the result i.e. 3 in the new linked list. Move to the
next one of both linked lists L1 and L2, perform the same
operation. In case the sum >= 10 then you apply the same rule
you would do to regular addition problem i.e. divide the sum
by 10 keep the remainder and push to the new linked
list. Don't forget to carry, 1, to the next operation. In case
one linked list is smaller than the other, you can safely
assume it is 0..
Example 2:
Input: L1 = 1 > 2 > 3 > 4 > 5
L2 = 6 > 5 > 5
Output: 1 > 3 > 0 > 0 > 0
Operation:
a) 1st member of L1 = 5 and 1st member of L2 = 5
b) 5 + 5 = 10
c) 0 pushed to the new linked list.
d) carry forward 1.
e) 2nd member of L1 = 4 and 2nd member of L2 = 5
f) 4 + 5 + 1 (carry) = 10
h) 0 again pushed to the new linked list.
i) carry forward 1.
j) 3rd member of L1 = 3 and 3rd member of L2 = 6
k) 3 + 6 + 1 (carry) = 10
l) 0 pshed to the new linked list.
m) carry forward 1.
n) 4th member of L1 = 2 and assume 0 as the 4th member of
L2 since there are only 3 members.
o) 2 + 1 (carry) = 3
p) 3 pushed to the new linked list.
q) 5th member of L1 = 1 and assume 0 as the 5th member of
L2 since there are only 3 members.
r) 1 + 0 = 1
s) 1 pushed to the new linked list.
So the new linked list now have: 1 > 3 > 0 > 0 > 0.
The above suggestion is one way, not necessarily the best
way to deal with it.
There are many ways to describe linked lists. In Perl
I
could use a simple array, as splicing allows all operations
that could be done with linked lists. Furthermore, as each
element contains only one digit, I could represent the array by a
string. Finally, strings can represent numbers. This suggest a
trivial oneliner solution. Is it cheating?
Example 1:
perl E '($A,$B)=map {join "", split /\s*>\s*/, $_} @ARGV;'\
E 'say join ">", split "", $A+$B;' "1>2>3" "3>2>1"
Results:
4>4>4
Example 2:
perl E '($A,$B)=map {join "", split /\s*>\s*/, $_} @ARGV;'\
E 'say join ">", split "", $A+$B;' "1>2>3>4>5" "6>5>5"
Results:
1>3>0>0>0
The longer version:
# Perl weekly challenge 129
# Task 2: add linked lists
#
# See https://wlmb.github.io/2021/09/06/PWC129/#task2addlinkedlists
use warnings;
use strict;
use v5.12;
use List::Util qw(all);
use bigint; # to allow large lists
my @A=split /\s*>\s*/, shift @ARGV;
my @B=split /\s*>\s*/, shift @ARGV;
die "Usage: ./ch2.pl l1 l2 with list arguments of the form \"dN...d2>d1>d0\""
unless all {m/^\d$/} @A, @B;
my $A=join '', @A;
my $B=join '', @B;
my $length=@A@B;
my $indent_A=$length<0?" "x($length):"";
my $indent_B=$length>0?" "x $length :"";
say "Input: L1=$indent_A", join ">", @A;
say " L2=$indent_B", join ">", @B;
say "Output: ", join ">", split '', $A+$B;
Example 1:
./ch2.pl "1>2>3" "3>2>1"
Results:
Input: L1=1>2>3
L2=3>2>1
Output: 4>4>4
Example 2:
./ch2.pl "1>2>3>4>5" "6>5>5"
Results:
Input: L1=1>2>3>4>5
L2= 6>5>5
Output: 1>3>0>0>0