diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2021-01-10 06:06:35 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-01-10 06:06:35 +0000 |
| commit | 27bded500f98ff5dafdb807e805dc261e1be40c4 (patch) | |
| tree | 282a2e2dbfc65b9a95a608947ddfcd9571dbaa38 /challenge-094 | |
| parent | 617bcce441d8b9caf1817bbe1ae16893720c8bcd (diff) | |
| parent | 529885c2a2acf7f20cd4e6f34524e462b536dd32 (diff) | |
| download | perlweeklychallenge-club-27bded500f98ff5dafdb807e805dc261e1be40c4.tar.gz perlweeklychallenge-club-27bded500f98ff5dafdb807e805dc261e1be40c4.tar.bz2 perlweeklychallenge-club-27bded500f98ff5dafdb807e805dc261e1be40c4.zip | |
Merge pull request #3192 from jo-37/contrib
Command line handling for challenges 093 / 094
Diffstat (limited to 'challenge-094')
| -rwxr-xr-x[-rw-r--r--] | challenge-094/jo-37/perl/ch-1.pl | 61 | ||||
| -rwxr-xr-x[-rw-r--r--] | challenge-094/jo-37/perl/ch-2.pl | 189 |
2 files changed, 174 insertions, 76 deletions
diff --git a/challenge-094/jo-37/perl/ch-1.pl b/challenge-094/jo-37/perl/ch-1.pl index a6725762ba..0e8dc4860b 100644..100755 --- a/challenge-094/jo-37/perl/ch-1.pl +++ b/challenge-094/jo-37/perl/ch-1.pl @@ -1,28 +1,53 @@ -#!/usr/bin/perl +#!/usr/bin/perl -s use v5.16; use Test2::V0; use experimental 'postderef'; +our $examples; + +run_examples() if $examples; # does not return + +say(<<EOS), exit unless @ARGV; +Usage: $0 [-examples] [word ...] + +-examples + runs the given examples + +word ... + use given words as input +EOS + +# Apply "anagroup" to @ARGV and convert the result into the requested +# format. +say '[ ' . + (join ', ', map { + '(' . (join ', ', map {qq{"$_"}} @$_) . ')' + } anagroup(@ARGV)) . + ' ]'; + # Group given strings by anagrams. sub anagroup { - # Hash to collect anagrams by a canonical key. - my %anagroup; - - # Split strings into characters, sort and rejoin to gain a - # "canonical anagram", decorate each string with its canonical - # anagram and collect the strings within the prepared hash by - # canonical key. - push $anagroup{$_->[0]}->@*, $_->[1] - foreach map {[join('', sort {$a cmp $b} split //), $_]} @_; - - # Sort the canonical anagrams and retrieve the corresponding string - # lists. (The sort is required for a stable result only.) - map {$anagroup{$_}} sort keys %anagroup; + # Hash to collect anagrams by a canonical key. + my %anagroup; + + # Split strings into characters, sort and rejoin to gain a + # "canonical anagram", decorate each string with its canonical + # anagram and collect the strings within the prepared hash by + # canonical key. + push $anagroup{$_->[0]}->@*, $_->[1] + foreach map {[join('', sort split //), $_]} @_; + + # Sort the canonical anagrams and retrieve the corresponding string + # lists. (The sort is required for a stable result only.) + map {$anagroup{$_}} sort keys %anagroup; } -is [anagroup qw(opt bat saw tab pot top was)], - [[qw(bat tab)], [qw(saw was)], [qw(opt pot top)]], 'Example 1'; -is [anagroup 'x'], [['x']], 'Example 2'; +sub run_examples { + is [anagroup qw(opt bat saw tab pot top was)], + [[qw(bat tab)], [qw(saw was)], [qw(opt pot top)]], 'Example 1'; + is [anagroup 'x'], [['x']], 'Example 2'; -done_testing; + done_testing; + exit; +} diff --git a/challenge-094/jo-37/perl/ch-2.pl b/challenge-094/jo-37/perl/ch-2.pl index 816dd3aa00..d16577d410 100644..100755 --- a/challenge-094/jo-37/perl/ch-2.pl +++ b/challenge-094/jo-37/perl/ch-2.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/perl -s use v5.16; use warnings FATAL => 'all'; @@ -6,7 +6,106 @@ no warnings 'recursion'; use experimental qw(postderef signatures); use Data::Dump; -# $::verbose = 1; +our ($mode, $examples, $verbose); +$mode ||= 'NLR'; + +run_examples() if $examples; # does not return + +say(<<EOS), exit unless @ARGV; +usage: $0 [-examples] [-verbose] [-mode=MODE] [node ...] + +-examples + run examples from challenge + +-verbose + print diagnostic information + +-mode=MODE + select traversal mode, any permutation of N, L, R. Default: NLR + see: + https://en.wikipedia.org/wiki/Tree_traversal#Depth-first_search_of_binary_tree + + +node ... + build binary tree from given nodes. Each node has the form: + id:value[:left[:right]] + where + id is a unique node identifier + value is the node's value + left is the id of the left child node (may be missing or empty) + right is the id of the right child node (may be missing) + The nodes may be specified in any order, but the root node must have + an id of 'ROOT'. The given example could be written as + ROOT:1:n2:n3 n2:2:n4:n5 n3:3 n4:4 n5:5:n6:n7 n6:6 n7:7 +EOS + +# @ARGV to BinaryTree +my $tree = build_tree(@ARGV); +dd $tree if $verbose; + +my $list = LinkedList->new; + +# Convert +flatten_tree($tree, $list, $mode); +dd $list if $verbose; + +# Format output +say "$mode: ", join ' -> ', $list->as_array; + +# Build a binary tree from the given list of nodes +sub build_tree { + # capture nodes + my %nodes = map { + my ($key, %val); ($key, @val{qw(val left right)}) = split /:/; + ($key => \%val) + } @_; + dd %nodes if $verbose; + + # dynamically build the tree from the given nodes while traversing + my $tree = BinaryTree->new('ROOT'); + $tree->traverse('NLR', sub { + my %node = $nodes{$_->[0]}->%*; + $_->[0] = $node{val}; + $_->[1] = [$node{left}] if $node{left}; + $_->[2] = [$node{right}] if $node{right}; + }); + + $tree; +} + +# The "glue" for this task: traverse given binary tree and build a +# linked list from the visited nodes. +sub flatten_tree ($tree, $list, $mode) { + $tree->traverse($mode, sub { + # Need to take special care at the head node. + $list ? $list->add($_->[0])->next : + $list->unshift($_->[0])->head + }); +} + +sub run_examples { + # Construct the binary tree from example 1. + my $tree = BinaryTree->new(1, + [2, + [4], + [5, + [6], + [7], + ], + ], + [3]); + dd $tree if $verbose; + + # Traverse the tree in different modes, where NLR solves this task. + foreach my $mode (qw(NLR LNR RNL LRN)) { + my $list = LinkedList->new; + flatten_tree($tree, $list, $mode); + dd $list if $verbose; + say "$mode: ", join ' -> ', $list->as_array; + } + exit; +} + package LinkedList; # Minimal object implementation of a singly linked list providing just @@ -23,60 +122,60 @@ package LinkedList; # Constructor for an empty list. sub new ($class) { - bless [], $class; + bless [], $class; } # A list in boolean context shall be true when positioned on an existing # node. Returns false after iterating beyond the last node or if there # are no nodes at all. use overload - bool => sub ($self, $, $) {!!$self->[0]}; + bool => sub ($self, $, $) {!!$self->[0]}; # Getter for the current node's data. sub data ($self) { - $self->[0][1]; + $self->[0][1]; } # Advance to the next node. sub next ($self) { - $self->[0] = $self->[0][0]; - - # Enable method chaining. - $self; + $self->[0] = $self->[0][0]; + + # Enable method chaining. + $self; } # Reset the current node to the head node. sub head ($self) { - $self->[0] = $self->[1]; + $self->[0] = $self->[1]; - # Enable method chaining. - $self; + # Enable method chaining. + $self; } # Insert a new node after the current node. This operation cannot be # used to insert a (new) head node - use "unshift" instead. sub add ($self, $data) { - $self->[0][0] = [$self->[0][0], $data]; + $self->[0][0] = [$self->[0][0], $data]; - # Enable method chaining. - $self; + # Enable method chaining. + $self; } # Retrieve node data as an array, starting from the head node. sub as_array ($self) { - my @arr; - for ($self->head; $self; $self->next) { - push @arr, $self->data; - } - @arr; + my @arr; + for ($self->head; $self; $self->next) { + push @arr, $self->data; + } + @arr; } # Insert a new head node. sub unshift ($self, $data) { - $self->[1] = [$self->[1], $data]; + $self->[1] = [$self->[1], $data]; - # Enable method chaining. - $self; + # Enable method chaining. + $self; } @@ -96,7 +195,7 @@ package BinaryTree; # - an optional left sub tree # - an optional right sub tree sub new ($class, $data, $left=undef, $right=undef) { - bless [$data, $left, $right], $class; + bless [$data, $left, $right], $class; } # Depth-first traversal of the binary tree starting from its root. The @@ -105,39 +204,13 @@ sub new ($class, $data, $left=undef, $right=undef) { # 'R' for the right sub tree. See # https://en.wikipedia.org/wiki/Tree_traversal#Depth-first_search_of_binary_tree # The code ref is called for every node according to the specified -# processing order with $_ set to the current node's data. +# processing order with $_ set to the current node. sub traverse ($self, $mode, $code) { - # Recursively process the tree in the specified order. Nodes are - # not blessed and thus have no methods. - foreach (split //, $mode) { - do {local $_ = $self->[0]; $code->()} if /^N$/; - traverse($self->[1], $mode, $code) if /^L$/ && $self->[1]; - traverse($self->[2], $mode, $code) if /^R$/ && $self->[2]; - } -} - - -package main; - -# Construct the binary tree from example 1. -my $tree = BinaryTree->new(1, - [2, - [4], - [5, - [6], - [7], - ], - ], - [3]); -dd $tree if $::verbose; - -# Traverse the tree in different modes, where NLR solves this task. -foreach my $mode (qw(NLR LNR RNL LRN)) { - my $list = LinkedList->new; - $tree->traverse($mode, sub { - # Need to take special care at the head node. - $list ? $list->add($_)->next : $list->unshift($_)->head - }); - dd $list if $::verbose; - say "$mode: ", join ' -> ', $list->as_array; + # Recursively process the tree in the specified order. Nodes are + # not blessed and thus have no methods. + foreach (split //, $mode) { + do {local $_ = $self; $code->()} if /^N$/; + traverse($self->[1], $mode, $code) if /^L$/ && $self->[1]; + traverse($self->[2], $mode, $code) if /^R$/ && $self->[2]; + } } |
