diff options
| author | Jörg Sommrey <28217714+jo-37@users.noreply.github.com> | 2021-02-01 14:38:35 +0100 |
|---|---|---|
| committer | Jörg Sommrey <28217714+jo-37@users.noreply.github.com> | 2021-02-06 10:56:35 +0100 |
| commit | 6e5aead601dec2908fed3735704d638991ed31fc (patch) | |
| tree | 5d4e4d35b41d8beebf9c542ab69a68f2fb2174d2 | |
| parent | 03b72227bc5710d91e03e35fd166c9b0e5e54975 (diff) | |
| download | perlweeklychallenge-club-6e5aead601dec2908fed3735704d638991ed31fc.tar.gz perlweeklychallenge-club-6e5aead601dec2908fed3735704d638991ed31fc.tar.bz2 perlweeklychallenge-club-6e5aead601dec2908fed3735704d638991ed31fc.zip | |
Solution to task 2
| -rwxr-xr-x | challenge-098/jo-37/perl/ch-2.pl | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/challenge-098/jo-37/perl/ch-2.pl b/challenge-098/jo-37/perl/ch-2.pl new file mode 100755 index 0000000000..2ae13d84a1 --- /dev/null +++ b/challenge-098/jo-37/perl/ch-2.pl @@ -0,0 +1,109 @@ +#!/usr/bin/perl -s + +use v5.16; +use Test2::V0; +use warnings FATAL => 'all'; +use List::MoreUtils 0.423 'lower_bound'; +use experimental 'signatures'; + +our ($tests, $examples, $verbose, $value); + +run_tests() if $tests || $examples; # does not return + +die <<EOS unless defined $value; +usage: $0 [-examples] [-tests] [-verbose] [-value=num [--] n1 n2...] + +-examples + run the examples from the challenge + +-tests + run some tests + +-verbose + show resulting index and array + +-value=num + number to insert or search for + +n1 n2... + sorted list of numbers + +EOS + +sub find_or_insert :prototype($\@); + + +### Input and Output + +say scalar find_or_insert $value, @ARGV; + + +### Implementation + +# Search for a value in the given sorted array insert it into the proper +# position if missing. +# +# Note 1: Has to be called with a true array as second argument. +# Note 2: Returns the index position when called in scalar context or a +# reference to the resulting array together with the index +# position in list context. +sub find_or_insert ($val, $arr) :prototype($\@) { + + # A binary search is the tool of choice to operate on sorted data. + # "lower_bound" provides the wanted index accordingly. Select zero + # for an empty array. + my $idx = @$arr ? lower_bound {$_ <=> $val} @$arr : 0; + + # Insert the value at the identified position if missing. Use a + # virtually appended 'inf' to force a "push" operation. + splice @$arr, $idx, 0, $val if ($arr->[$idx] // 'inf') > $val; + say "$idx: (@$arr)" if $verbose; + + # Return a reference to the resulting array and the index. + ($arr, $idx); +} + + +### Examples and tests + +sub run_tests { + SKIP: { + skip 'examples' unless $examples; + + my @a; + + @a = (1, 2, 3, 4); + is find_or_insert(3, @a), 2, 'example 1'; + is [@a], [1, 2, 3, 4], 'resulting array for example 1'; + + @a = (1, 3, 5, 7); + is find_or_insert(6, @a), 3, 'example 2'; + is [@a], [1, 3, 5, 6, 7], 'resulting array for example 2'; + + @a = (12, 14, 16, 18); + is find_or_insert(10, @a), 0, 'example 3'; + is [@a], [10, 12, 14, 16, 18], 'resulting array for example 3'; + + @a = (11, 13, 15, 17); + is find_or_insert(19, @a), 4, 'example 4'; + is [@a], [11, 13, 15, 17, 19], 'resulting array for example 4'; + } + + SKIP: { + skip 'tests' unless $tests; + + # Provide list context to retrieve the resulting array. + + is [find_or_insert 0, @{[]}], [[0], 0], + 'insert zero into empty list'; + + is [find_or_insert 0, @{[0]}], [[0], 0], + 'find zero'; + + is [find_or_insert -1, @{[0]}], [[-1, 0], 0], + 'insert negative value'; + } + + done_testing; + exit; +} |
