From 2a05f98302637a957d242511fb4ef94db4c6b716 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 18 Jan 2021 13:29:20 +0100 Subject: Given examples --- challenge-096/abigail/t/ctest.ini | 7 +++++++ challenge-096/abigail/t/input-1-1 | 2 ++ challenge-096/abigail/t/input-2-1 | 2 ++ challenge-096/abigail/t/output-1-1.exp | 2 ++ challenge-096/abigail/t/output-2-1.exp | 2 ++ 5 files changed, 15 insertions(+) create mode 100644 challenge-096/abigail/t/ctest.ini create mode 100644 challenge-096/abigail/t/input-1-1 create mode 100644 challenge-096/abigail/t/input-2-1 create mode 100644 challenge-096/abigail/t/output-1-1.exp create mode 100644 challenge-096/abigail/t/output-2-1.exp diff --git a/challenge-096/abigail/t/ctest.ini b/challenge-096/abigail/t/ctest.ini new file mode 100644 index 0000000000..1e78d5aadc --- /dev/null +++ b/challenge-096/abigail/t/ctest.ini @@ -0,0 +1,7 @@ +[names] +1-1 = Given examples +2-1 = Given examples + + +[1-1] +trim = 0 diff --git a/challenge-096/abigail/t/input-1-1 b/challenge-096/abigail/t/input-1-1 new file mode 100644 index 0000000000..ed78ab1367 --- /dev/null +++ b/challenge-096/abigail/t/input-1-1 @@ -0,0 +1,2 @@ +The Weekly Challenge + Perl and Raku are part of the same family diff --git a/challenge-096/abigail/t/input-2-1 b/challenge-096/abigail/t/input-2-1 new file mode 100644 index 0000000000..cdfe0772e5 --- /dev/null +++ b/challenge-096/abigail/t/input-2-1 @@ -0,0 +1,2 @@ +kitten sitting +sunday monday diff --git a/challenge-096/abigail/t/output-1-1.exp b/challenge-096/abigail/t/output-1-1.exp new file mode 100644 index 0000000000..a551829850 --- /dev/null +++ b/challenge-096/abigail/t/output-1-1.exp @@ -0,0 +1,2 @@ +Challenge Weekly The +family same the of part are Raku and Perl diff --git a/challenge-096/abigail/t/output-2-1.exp b/challenge-096/abigail/t/output-2-1.exp new file mode 100644 index 0000000000..f1e5eeed2d --- /dev/null +++ b/challenge-096/abigail/t/output-2-1.exp @@ -0,0 +1,2 @@ +3 +2 -- cgit From ace53ffec67794fec91f402c89dbb1f4d2c42bf8 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 18 Jan 2021 13:58:22 +0100 Subject: Perl solution for week 96/part 1 --- challenge-096/abigail/perl/ch-1.pl | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 challenge-096/abigail/perl/ch-1.pl diff --git a/challenge-096/abigail/perl/ch-1.pl b/challenge-096/abigail/perl/ch-1.pl new file mode 100644 index 0000000000..ddca656054 --- /dev/null +++ b/challenge-096/abigail/perl/ch-1.pl @@ -0,0 +1,33 @@ +#!/opt/perl/bin/perl + +use 5.032; + +use strict; +use warnings; +no warnings 'syntax'; + +use experimental 'signatures'; +use experimental 'lexical_subs'; + +# +# For the challenge description, see ../README.md +# + +# +# The challenge doesn't describe what a word is, or what to +# do with things which are neither words, nor whitespace, like +# punctuation. +# +# For instance, what should happen to the sentence: +# +# "The Weekly Challenge, Part 1!" +# +# So, we're using the easy way out, and assume anything which isn't +# whitespace to be part of a word. After all, the examples assumen +# all the world is ASCII letters and spaces. +# +# Which makes the excercise too trivial to be called a challenge. +# + +# Extract 'words', reverse the list, and print it. +say join " " => reverse /\S+/g for <>; -- cgit From 4f87b77d36d715e794302abb707da11eb736ba58 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 18 Jan 2021 14:21:13 +0100 Subject: AWK and Node.js solutions for week 96, part 1 --- challenge-096/abigail/README.md | 68 ++++++++++++++++++-------------------- challenge-096/abigail/awk/ch-1.awk | 10 ++++++ challenge-096/abigail/node/ch-1.js | 15 +++++++++ 3 files changed, 58 insertions(+), 35 deletions(-) create mode 100644 challenge-096/abigail/awk/ch-1.awk create mode 100644 challenge-096/abigail/node/ch-1.js diff --git a/challenge-096/abigail/README.md b/challenge-096/abigail/README.md index a82f466a38..60888652f5 100644 --- a/challenge-096/abigail/README.md +++ b/challenge-096/abigail/README.md @@ -1,62 +1,60 @@ # Solution by Abigail -## [Task 1](https://perlweeklychallenge.org/blog/perl-weekly-challenge-095/#TASK1): +## [Reverse Words](https://perlweeklychallenge.org/blog/perl-weekly-challenge-096/#TASK1) -You are given a number `$N`. +You are given a string `$S`. -Write a script to figure out if the given number is Palindrome. -Print `1` if true otherwise `0`. +Write a script to reverse the order of words in the given string. +The string may contain leading/trailing spaces. The string may have +more than one space between words in the string. Print the result +without leading/trailing spaces and there should be only one space +between words. ### Examples ~~~~ -Input: 1221 -Output: 1 +Input: $S = "The Weekly Challenge" +Output: "Challenge Weekly The" -Input: -101 -Output: 0, since -101 and 101- are not the same. - -Input: 90 -Output: 0 +Input: $S = " Perl and Raku are part of the same family " +Output: "family same the of part are Raku and Perl" ~~~~ ### Solutions -* [awk](awk/ch-1.c) -* [C](c/ch-1.c) -* [Node](node/ch-1.js) +* [AWK](awk/ch-1.awk) +* [Node.js](node/ch-1.js) * [Perl](perl/ch-1.pl) -* [Python](python/ch-1.py) ### Blog -[Perl Weekly Challenge 95, Part 1](https://wp.me/pcxd30-kq) -## [Task 2](https://perlweeklychallenge.org/blog/perl-weekly-challenge-095/#TASK2) +## [Edit Distance](https://perlweeklychallenge.org/blog/perl-weekly-challenge-096/#TASK2) -Write a script to demonstrate `Stack` operations like below: +You are given two strings `$S1` and `$S2`. -* `push($n)` - add $n to the stack -* `pop()` - remove the top element -* `top()` - get the top element -* `min()` - return the minimum element +Write a script to find out the minimum operations required to convert +`$S1` into `$S2`. The operations can be insert, remove or replace a +character. Please check out [Wikipedia +page](https://en.wikipedia.org/wiki/Edit_distance) for more information. ### Example ~~~~ -my $stack = Stack->new; -$stack->push(2); -$stack->push(-1); -$stack->push(0); -$stack->pop; # removes 0 -print $stack->top; # prints -1 -$stack->push(0); -print $stack->min; # prints -1 +Input: $S1 = "kitten"; $S2 = "sitting" +Output: 3 + +Operation 1: replace 'k' with 's' +Operation 2: replace 'e' with 'i' +Operation 3: insert 'g' at the end +~~~~ + +~~~~ +Input: $S1 = "sunday"; $S2 = "monday" +Output: 2 + +Operation 1: replace 's' with 'm' +Operation 2: replace 'u' with 'o' ~~~~ ### Solutions -* [awk](awk/ch-2.awk) -* [C](c/ch-2.c) -* [Node](node/ch-2.js) * [Perl](perl/ch-2.pl) -* [Python](python/ch-2.py) ### Blog -[Perl Weekly Challenge 95, Part 2](https://wp.me/pcxd30-ld) diff --git a/challenge-096/abigail/awk/ch-1.awk b/challenge-096/abigail/awk/ch-1.awk new file mode 100644 index 0000000000..744c154648 --- /dev/null +++ b/challenge-096/abigail/awk/ch-1.awk @@ -0,0 +1,10 @@ +# +# AWK splits lines on whitespace, making each field available +# in $1, $2, ..., etc. So, we just print the fields in reverse, +# followed by a space (or a newline after the last/first). +# +{ + for (i = NF; i; i --) { + printf "%s%s", $i, (i == 1 ? "\n" : " "); + } +} diff --git a/challenge-096/abigail/node/ch-1.js b/challenge-096/abigail/node/ch-1.js new file mode 100644 index 0000000000..b31524a686 --- /dev/null +++ b/challenge-096/abigail/node/ch-1.js @@ -0,0 +1,15 @@ +// +// Read STDIN. Split on newlines, filter out empty lines, then call "main". +// + require ("fs") +. readFileSync (0) // Read all. +. toString () // Turn it into a string. +. split ("\n") // Split on newlines. +. filter (_ => _ . length) // Filter out empty lines. +. map (_ => console . log (_ . trim () // Remove leading + // and trailing + // whitespace. + . split (/\s+/) // split ... + . reverse () // reverse ... + . join (" "))) // and recombine. +; -- cgit From b6b448564c1d62f1d4c623b9bce5f8a9f8d8b652 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 18 Jan 2021 14:40:04 +0100 Subject: Python solution for week 95, part 1 --- challenge-096/abigail/README.md | 1 + challenge-096/abigail/python/ch-1.py | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 challenge-096/abigail/python/ch-1.py diff --git a/challenge-096/abigail/README.md b/challenge-096/abigail/README.md index 60888652f5..c45d495eb6 100644 --- a/challenge-096/abigail/README.md +++ b/challenge-096/abigail/README.md @@ -23,6 +23,7 @@ Output: "family same the of part are Raku and Perl" * [AWK](awk/ch-1.awk) * [Node.js](node/ch-1.js) * [Perl](perl/ch-1.pl) +* [Python](python/ch-1.py) ### Blog diff --git a/challenge-096/abigail/python/ch-1.py b/challenge-096/abigail/python/ch-1.py new file mode 100644 index 0000000000..ddc34e2633 --- /dev/null +++ b/challenge-096/abigail/python/ch-1.py @@ -0,0 +1,6 @@ +import fileinput + +for line in fileinput . input (): + words = line . strip () . split () + words . reverse () + print (" " . join (words)) -- cgit From 6be85bd8cd6960a0fd063e67b78f88b39df528e9 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 18 Jan 2021 15:10:35 +0100 Subject: C solution for week 96/part 1 --- challenge-096/abigail/README.md | 1 + challenge-096/abigail/c/ch-1.c | 66 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 challenge-096/abigail/c/ch-1.c diff --git a/challenge-096/abigail/README.md b/challenge-096/abigail/README.md index c45d495eb6..ee7bed56c2 100644 --- a/challenge-096/abigail/README.md +++ b/challenge-096/abigail/README.md @@ -20,6 +20,7 @@ Output: "family same the of part are Raku and Perl" ~~~~ ### Solutions +* [C](c/ch-1.c) * [AWK](awk/ch-1.awk) * [Node.js](node/ch-1.js) * [Perl](perl/ch-1.pl) diff --git a/challenge-096/abigail/c/ch-1.c b/challenge-096/abigail/c/ch-1.c new file mode 100644 index 0000000000..22ebafd404 --- /dev/null +++ b/challenge-096/abigail/c/ch-1.c @@ -0,0 +1,66 @@ +# include +# include +# include +# include + +int main (void) { + char * line = NULL; + size_t len = 0; + size_t strlen; + + while ((strlen = getline (&line, &len, stdin)) != -1) { + char * line_ptr = line; + size_t end = strlen; + size_t begin; + size_t output = 0; + while (end > 0) { + /* + * Skip tailing whitespace + */ + while (end > 0 && isspace (line [end - 1])) { + end --; + } + + /* + * 'end' now just after the end of a word, or + * at the beginning of the string; if the latter, + * there is nothing left to print. + */ + + if (end <= 0) { + break; + } + + /* + * Find the beginning of a word + */ + begin = end - 1; + while (begin > 0 && !isspace (line [begin - 1])) { + begin --; + } + + /* + * Extract the word out of the string: allocate memory, + * and copy the right part of the input. + */ + char * word; + if ((word = malloc ((end - begin + 1) * sizeof (char))) == NULL) { + fprintf (stderr, "Out of memory\n"); + exit (1); + } + stpncpy (word, line + begin, end - begin); + + /* + * Print the string, prepended (except the first printed word) + * by a space. + */ + printf ("%s%s", output ++ ? " " : "", word); + + end = begin; + } + printf ("\n"); + } + free (line); + + return (0); +} -- cgit From a1cee94025af8df9d613d8789839c208e453a914 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 18 Jan 2021 16:35:53 +0100 Subject: Ruby solution for week 95/part 1 --- challenge-096/abigail/README.md | 1 + challenge-096/abigail/ruby/ch-1.rb | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 challenge-096/abigail/ruby/ch-1.rb diff --git a/challenge-096/abigail/README.md b/challenge-096/abigail/README.md index ee7bed56c2..ea55819653 100644 --- a/challenge-096/abigail/README.md +++ b/challenge-096/abigail/README.md @@ -25,6 +25,7 @@ Output: "family same the of part are Raku and Perl" * [Node.js](node/ch-1.js) * [Perl](perl/ch-1.pl) * [Python](python/ch-1.py) +* [Ruby](ruby/ch-1.py) ### Blog diff --git a/challenge-096/abigail/ruby/ch-1.rb b/challenge-096/abigail/ruby/ch-1.rb new file mode 100644 index 0000000000..064f780345 --- /dev/null +++ b/challenge-096/abigail/ruby/ch-1.rb @@ -0,0 +1,3 @@ +ARGF . each_line do |_| + puts ((_ . split (/\s+/)) . grep (/\S/)) . reverse . join (" ") +end -- cgit From 4a2818e3550e3f914e285bc0bc67b10c61c24cf5 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 18 Jan 2021 17:05:29 +0100 Subject: Perl solution for week 96, part 2 --- challenge-096/abigail/perl/ch-2.pl | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 challenge-096/abigail/perl/ch-2.pl diff --git a/challenge-096/abigail/perl/ch-2.pl b/challenge-096/abigail/perl/ch-2.pl new file mode 100644 index 0000000000..7fc41b2604 --- /dev/null +++ b/challenge-096/abigail/perl/ch-2.pl @@ -0,0 +1,46 @@ + + +use 5.032; + +use strict; +use warnings; +no warnings 'syntax'; + +use experimental 'signatures'; +use experimental 'lexical_subs'; + +use List::Util 'min'; + +# +# This is an implementation of the Wagner Fischer algorithm, which +# calculates the Levenshtein distance. +# +# See https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm +# +sub LevenshteinDistance ($first, $second) { + ($first, $second) = ($second, $first) if length ($first) < + length ($second); + my $distance; + for (my $i = 0; $i <= length ($first); $i ++) { + for (my $j = 0; $j <= length ($second); $j ++) { + $$distance [$i] [$j] = + $j == 0 ? $i + : $i == 0 ? $j + : min ($$distance [$i - 1] [$j] + 1, + $$distance [$i] [$j - 1] + 1, + $$distance [$i - 1] [$j - 1] + + (substr ($first, $i - 1, 1) eq + substr ($second, $j - 1, 1) ? 0 : 1)) + } + # + # We only need the previous row; this reduces the memory + # from O (N * M) to O (min (N, M)), where N and M are the + # lengths of the input strings. + # + undef $$distance [$i - 1] if $i; + } + $$distance [-1] [-1]; +} + + +say LevenshteinDistance /\S+/g for <>; -- cgit From 627ff2ed726fc3b15e0606b0570e10262a2553e6 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 18 Jan 2021 17:31:57 +0100 Subject: Another example for part 2 --- challenge-096/abigail/t/ctest.ini | 1 + challenge-096/abigail/t/input-2-2 | 1 + challenge-096/abigail/t/output-2-2.exp | 1 + 3 files changed, 3 insertions(+) create mode 100644 challenge-096/abigail/t/input-2-2 create mode 100644 challenge-096/abigail/t/output-2-2.exp diff --git a/challenge-096/abigail/t/ctest.ini b/challenge-096/abigail/t/ctest.ini index 1e78d5aadc..99eb989ad5 100644 --- a/challenge-096/abigail/t/ctest.ini +++ b/challenge-096/abigail/t/ctest.ini @@ -1,6 +1,7 @@ [names] 1-1 = Given examples 2-1 = Given examples +2-2 = Wikipedia example [1-1] diff --git a/challenge-096/abigail/t/input-2-2 b/challenge-096/abigail/t/input-2-2 new file mode 100644 index 0000000000..3575a4749f --- /dev/null +++ b/challenge-096/abigail/t/input-2-2 @@ -0,0 +1 @@ +sunday saturday diff --git a/challenge-096/abigail/t/output-2-2.exp b/challenge-096/abigail/t/output-2-2.exp new file mode 100644 index 0000000000..00750edc07 --- /dev/null +++ b/challenge-096/abigail/t/output-2-2.exp @@ -0,0 +1 @@ +3 -- cgit From 6987a3e81c21dbc1bda95ced9fc5e352a337f37e Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 18 Jan 2021 17:57:25 +0100 Subject: Tiny optimization for perl solution for week 96, part 2 --- challenge-096/abigail/perl/ch-2.pl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/challenge-096/abigail/perl/ch-2.pl b/challenge-096/abigail/perl/ch-2.pl index 7fc41b2604..bb58c84569 100644 --- a/challenge-096/abigail/perl/ch-2.pl +++ b/challenge-096/abigail/perl/ch-2.pl @@ -24,8 +24,7 @@ sub LevenshteinDistance ($first, $second) { for (my $i = 0; $i <= length ($first); $i ++) { for (my $j = 0; $j <= length ($second); $j ++) { $$distance [$i] [$j] = - $j == 0 ? $i - : $i == 0 ? $j + $i == 0 || $j == 0 ? $i + $j : min ($$distance [$i - 1] [$j] + 1, $$distance [$i] [$j - 1] + 1, $$distance [$i - 1] [$j - 1] + -- cgit From 7209da1bc64d0ad614b51fdaff8f188715d8f81d Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 18 Jan 2021 18:10:38 +0100 Subject: Node solution for week 96, part 2 --- challenge-096/abigail/README.md | 1 + challenge-096/abigail/node/ch-2.js | 43 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 challenge-096/abigail/node/ch-2.js diff --git a/challenge-096/abigail/README.md b/challenge-096/abigail/README.md index ea55819653..b19e1c3934 100644 --- a/challenge-096/abigail/README.md +++ b/challenge-096/abigail/README.md @@ -58,6 +58,7 @@ Operation 2: replace 'u' with 'o' ~~~~ ### Solutions +* [Node.js](node/ch-2.js) * [Perl](perl/ch-2.pl) ### Blog diff --git a/challenge-096/abigail/node/ch-2.js b/challenge-096/abigail/node/ch-2.js new file mode 100644 index 0000000000..03f423b2ec --- /dev/null +++ b/challenge-096/abigail/node/ch-2.js @@ -0,0 +1,43 @@ +// +// Read STDIN. Split on newlines, filter out empty lines, then call "main". +// + require ("fs") +. readFileSync (0) // Read all. +. toString () // Turn it into a string. +. split ("\n") // Split on newlines. +. filter (_ => _ . length) // Filter out empty lines. +. map (_ => console . log (LevenshteinDistance (_ . split (/\s+/)))) +; + +// +// This is an implementation of the Wagner Fischer algorithm, which +// calculates the Levenshtein distance. +// +// See https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm +// +function LevenshteinDistance (strings) { + let first = strings [0] . split (""); + let second = strings [1] . split (""); + + let distance = []; + + let N = first . length; + let M = second . length; + + for (let i = 0; i <= N; i ++) { + distance [i] = []; + for (let j = 0; j <= M; j ++) { + distance [i] [j] = + i == 0 || j == 0 ? i + j + : Math . min (distance [i - 1] [j] + 1, + distance [i] [j - 1] + 1, + distance [i - 1] [j - 1] + + (first [i - 1] == + second [j - 1] ? 0 : 1)) + } + if (i) { + distance [i - 1] = 0 + } + } + return distance [N] [M] +} -- cgit From 7427859740c652344f72753829d12358b36f9807 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 18 Jan 2021 18:52:27 +0100 Subject: AWK solution for week 96/part 2 --- challenge-096/abigail/awk/ch-2.awk | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 challenge-096/abigail/awk/ch-2.awk diff --git a/challenge-096/abigail/awk/ch-2.awk b/challenge-096/abigail/awk/ch-2.awk new file mode 100644 index 0000000000..08cebccb4e --- /dev/null +++ b/challenge-096/abigail/awk/ch-2.awk @@ -0,0 +1,26 @@ +# +# Return the minimum of 3 values +# +function min (a, b, c) { + return a < b ? a < c ? a : c\ + : b < c ? b : c +} + +# +# This is an implementation of the Wagner Fischer algorithm, which +# calculates the Levenshtein distance. +# +# See https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm +# +{ + for (i = 0; i <= length ($1); i ++) { + for (j = 0; j <= length ($2); j ++) { + distance [i, j] = i == 0 || j == 0 ? i + j\ + : min(distance [i - 1, j] + 1, + distance [i, j - 1] + 1, + distance [i - 1, j - 1] +\ + (substr ($1, i, 1) == substr ($2, j, 1) ? 0 : 1)) + } + } + print distance [length ($1), length ($2)] +} -- cgit From d83a719fd0a80c8852e4187fe6f68e5833438417 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 18 Jan 2021 20:43:51 +0100 Subject: C solution for week 96, part 2 --- challenge-096/abigail/README.md | 2 + challenge-096/abigail/c/ch-2.c | 128 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 challenge-096/abigail/c/ch-2.c diff --git a/challenge-096/abigail/README.md b/challenge-096/abigail/README.md index b19e1c3934..b15e417559 100644 --- a/challenge-096/abigail/README.md +++ b/challenge-096/abigail/README.md @@ -58,6 +58,8 @@ Operation 2: replace 'u' with 'o' ~~~~ ### Solutions +* [AWK](awk/ch-2.awk) +* [C](c/ch-2.c) * [Node.js](node/ch-2.js) * [Perl](perl/ch-2.pl) diff --git a/challenge-096/abigail/c/ch-2.c b/challenge-096/abigail/c/ch-2.c new file mode 100644 index 0000000000..73f35b1c0a --- /dev/null +++ b/challenge-096/abigail/c/ch-2.c @@ -0,0 +1,128 @@ +# include +# include +# include +# include + +/* + * Return the minimum of three size_t values. + */ +size_t min3 (size_t a, size_t b, size_t c) { + return a < b ? a < c ? a : c + : b < c ? b : c; +} + +/* + * This is an implementation of the Wagner Fischer algorithm, which + * calculates the Levenshtein distance. + * + * See https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm + */ +size_t LevenshteinDistance (char * first, size_t n, + char * second, size_t m) { + + /* + * If 'first' is the shorter string, swap the two strings. + * This reduces the memory usage. + */ + if (n < m) { + char * tmp = first; + size_t t = n; + first = second; + second = tmp; + n = m; + m = t; + } + + size_t ** distance; + if ((distance = malloc ((n + 1) * sizeof (size_t *))) == NULL) { + fprintf (stderr, "Out of memory\n"); + exit (1); + } + for (size_t i = 0; i <= n; i ++) { + if ((distance [i] = malloc ((m + 1) * sizeof (size_t))) == NULL) { + fprintf (stderr, "Out of memory\n"); + exit (1); + } + for (size_t j = 0; j <= m; j ++) { + distance [i] [j] = i == 0 || j == 0 ? i + j + : min3 (distance [i - 1] [j] + 1, + distance [i] [j - 1] + 1, + distance [i - 1] [j - 1] + + (first [i - 1] == second [j - 1] ? 0 : 1)); + } + if (i) { + /* + * We only need the previous row; freeing the memory of rows + * we no longer need, reduces the memory usage from + * Theta (n * m) to O (min (n, m)) + */ + free (distance [i - 1]); + } + } + size_t out = distance [n] [m]; + free (distance [n]); + free (distance); + return (out); +} + + +int main (void) { + char * line = NULL; + size_t len = 0; + size_t str_len; + + while ((str_len = getline (&line, &len, stdin)) != -1) { + char * line_ptr = line; + /* + * Skip any leading whitespace + */ + while (isspace (*line_ptr)) { + line_ptr ++; + } + /* + * We're now at the start of the first word; + * scan the word, count its length. + */ + char * first = line_ptr; + size_t n = 0; + + while (!isspace (*line_ptr)) { + line_ptr ++; + n ++; + } + + /* + * Terminate the first word, and advance our pointer. + */ + *line_ptr ++ = '\0'; + + /* + * Skip over any subsequent whitespace + */ + while (isspace (*line_ptr)) { + line_ptr ++; + } + + /* + * We're now at the beginning of the second word; + * scan it, and count its length. + */ + char * second = line_ptr; + size_t m = 0; + + while (*line_ptr && !isspace (*line_ptr)) { + line_ptr ++; + m ++; + } + + /* + * Terminate the second word, before any trailing whitespace + */ + *line_ptr ++ = '\0'; + + printf ("%zu\n", LevenshteinDistance (first, n, second, m)); + } + free (line); + + return (0); +} -- cgit From 244e676bc1ed3e802597168c002398615fbcb062 Mon Sep 17 00:00:00 2001 From: Abigail Date: Tue, 19 Jan 2021 13:40:16 +0100 Subject: Fix order of solutions --- challenge-096/abigail/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/challenge-096/abigail/README.md b/challenge-096/abigail/README.md index b15e417559..b0b0617ad2 100644 --- a/challenge-096/abigail/README.md +++ b/challenge-096/abigail/README.md @@ -20,8 +20,8 @@ Output: "family same the of part are Raku and Perl" ~~~~ ### Solutions -* [C](c/ch-1.c) * [AWK](awk/ch-1.awk) +* [C](c/ch-1.c) * [Node.js](node/ch-1.js) * [Perl](perl/ch-1.pl) * [Python](python/ch-1.py) @@ -62,5 +62,6 @@ Operation 2: replace 'u' with 'o' * [C](c/ch-2.c) * [Node.js](node/ch-2.js) * [Perl](perl/ch-2.pl) +* [Python](python/ch-2.py) ### Blog -- cgit From b3fd5101407177b4d9a8e2d41b3e063269cee6ba Mon Sep 17 00:00:00 2001 From: Abigail Date: Tue, 19 Jan 2021 13:42:51 +0100 Subject: Python solution for week 96, part 2. --- challenge-096/abigail/python/ch-2.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 challenge-096/abigail/python/ch-2.py diff --git a/challenge-096/abigail/python/ch-2.py b/challenge-096/abigail/python/ch-2.py new file mode 100644 index 0000000000..deaeff14cf --- /dev/null +++ b/challenge-096/abigail/python/ch-2.py @@ -0,0 +1,21 @@ +import fileinput + +def LevenshteinDistance (first, second): + n = len (first) + m = len (second) + distance = [] + for i in range (n + 1): + distance . append ([]) + for j in range (m + 1): + distance [i] . append (i + j if i == 0 or j == 0 else + min (distance [i - 1] [j] + 1, + distance [i] [j - 1] + 1, + distance [i - 1] [j - 1] + + (0 if first [i - 1] == + second [j - 1] else 1))) + return distance [n] [m] + + +for line in fileinput . input (): + words = line . strip () . split () + print LevenshteinDistance (words [0], words [1]) -- cgit From 6a8e97190d55b1e0f94318e4e0316e50de7415c0 Mon Sep 17 00:00:00 2001 From: Abigail Date: Tue, 19 Jan 2021 13:43:39 +0100 Subject: lua solution for week 96, part 1 --- challenge-096/abigail/README.md | 1 + challenge-096/abigail/lua/ch-1.lua | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 challenge-096/abigail/lua/ch-1.lua diff --git a/challenge-096/abigail/README.md b/challenge-096/abigail/README.md index b0b0617ad2..31f4073f0d 100644 --- a/challenge-096/abigail/README.md +++ b/challenge-096/abigail/README.md @@ -22,6 +22,7 @@ Output: "family same the of part are Raku and Perl" ### Solutions * [AWK](awk/ch-1.awk) * [C](c/ch-1.c) +* [lua](lua/ch-1.lua) * [Node.js](node/ch-1.js) * [Perl](perl/ch-1.pl) * [Python](python/ch-1.py) diff --git a/challenge-096/abigail/lua/ch-1.lua b/challenge-096/abigail/lua/ch-1.lua new file mode 100644 index 0000000000..68d1c5eb86 --- /dev/null +++ b/challenge-096/abigail/lua/ch-1.lua @@ -0,0 +1,14 @@ +for line in io . lines () do + -- + -- Extract words and put them into an array, in reverse. + -- + words = {} + for str in string . gmatch (line, "[^ ]+") do + table . insert (words, 1, str) + end + + -- + -- Print the words + -- + io . write (table . concat (words, " "), "\n") +end -- cgit From b15a7dd19167fadcd7ef68d7807fb0915935fc5c Mon Sep 17 00:00:00 2001 From: Abigail Date: Tue, 19 Jan 2021 17:54:23 +0100 Subject: Make lua variables lexical --- challenge-096/abigail/lua/ch-1.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenge-096/abigail/lua/ch-1.lua b/challenge-096/abigail/lua/ch-1.lua index 68d1c5eb86..9c4b1de913 100644 --- a/challenge-096/abigail/lua/ch-1.lua +++ b/challenge-096/abigail/lua/ch-1.lua @@ -2,7 +2,7 @@ for line in io . lines () do -- -- Extract words and put them into an array, in reverse. -- - words = {} + local words = {} for str in string . gmatch (line, "[^ ]+") do table . insert (words, 1, str) end -- cgit From aafab4118e1ed9b94a7f2c16cf4457d79ab53f77 Mon Sep 17 00:00:00 2001 From: Abigail Date: Tue, 19 Jan 2021 18:53:19 +0100 Subject: lua solution for week 96, part 2 --- challenge-096/abigail/README.md | 1 + challenge-096/abigail/lua/ch-2.lua | 56 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 challenge-096/abigail/lua/ch-2.lua diff --git a/challenge-096/abigail/README.md b/challenge-096/abigail/README.md index 31f4073f0d..b80b3476b1 100644 --- a/challenge-096/abigail/README.md +++ b/challenge-096/abigail/README.md @@ -61,6 +61,7 @@ Operation 2: replace 'u' with 'o' ### Solutions * [AWK](awk/ch-2.awk) * [C](c/ch-2.c) +* [lua](lua/ch-2.lua) * [Node.js](node/ch-2.js) * [Perl](perl/ch-2.pl) * [Python](python/ch-2.py) diff --git a/challenge-096/abigail/lua/ch-2.lua b/challenge-096/abigail/lua/ch-2.lua new file mode 100644 index 0000000000..bb1b042b19 --- /dev/null +++ b/challenge-096/abigail/lua/ch-2.lua @@ -0,0 +1,56 @@ +-- +-- This is an implementation of the Wagner Fischer algorithm, which +-- calculates the Levenshtein distance. +-- +-- See https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm +-- +function LevenshteinDistance (first, second) + local n = first : len () + local m = second : len () + if n < m + then + first, second = second, first + n, m = m, n + end + distances = {} + for i = 0, n do + distances [i] = {} + for j = 0, m do + if i == 0 or j == 0 + then + distances [i] [j] = i + j + else + local cost = 1 + if string . sub (first, i, i) == + string . sub (second, j, j) + then + cost = 0 + end + distances [i] [j] = math . min ( + distances [i - 1] [j] + 1, + distances [i] [j - 1] + 1, + distances [i - 1] [j - 1] + cost + ) + end + end + end + return distances [n] [m] +end + + +for line in io . lines () do + -- + -- Extract words and put them into an array. + -- + local words = {} + index = 0 + for str in string . gmatch (line, "[^ ]+") do + index = index + 1 + words [index] = str + end + + -- + -- Calculate the edit distance, and print the result. + -- + io . write (LevenshteinDistance (words [1], words [2]), "\n") +end -- cgit From 8efd5eca4066257d8d39aa1f25481b09e8bc7689 Mon Sep 17 00:00:00 2001 From: Abigail Date: Tue, 19 Jan 2021 19:45:56 +0100 Subject: Bash solution for week 96, part 1 --- challenge-096/abigail/README.md | 1 + challenge-096/abigail/bash/ch-1.sh | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 challenge-096/abigail/bash/ch-1.sh diff --git a/challenge-096/abigail/README.md b/challenge-096/abigail/README.md index b80b3476b1..3582807374 100644 --- a/challenge-096/abigail/README.md +++ b/challenge-096/abigail/README.md @@ -21,6 +21,7 @@ Output: "family same the of part are Raku and Perl" ### Solutions * [AWK](awk/ch-1.awk) +* [bash](sh/ch-1.sh) * [C](c/ch-1.c) * [lua](lua/ch-1.lua) * [Node.js](node/ch-1.js) diff --git a/challenge-096/abigail/bash/ch-1.sh b/challenge-096/abigail/bash/ch-1.sh new file mode 100644 index 0000000000..9122fae4e0 --- /dev/null +++ b/challenge-096/abigail/bash/ch-1.sh @@ -0,0 +1,21 @@ +# +# Read in a line from STDIN, split it on whitespace, +# put the result into an array 'words' +# +while read -a words +do + # + # Iterate over the words backwards, and print them. + # + for ((i = ${#words[@]} - 1; i >= 0; i --)); + do printf "%s" ${words[$i]} + # + # Print a newline after the final word; otherwise, + # print a space. + # + if (($i == 0)) + then printf "\n" + else printf " " + fi + done +done -- cgit From 8ed013c57480f076ff5da48f18b2ca86a86c4bba Mon Sep 17 00:00:00 2001 From: Abigail Date: Tue, 19 Jan 2021 20:22:03 +0100 Subject: Ruby solution for week 96, part 2 --- challenge-096/abigail/README.md | 3 ++- challenge-096/abigail/ruby/ch-2.rb | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 challenge-096/abigail/ruby/ch-2.rb diff --git a/challenge-096/abigail/README.md b/challenge-096/abigail/README.md index 3582807374..d715618651 100644 --- a/challenge-096/abigail/README.md +++ b/challenge-096/abigail/README.md @@ -27,7 +27,7 @@ Output: "family same the of part are Raku and Perl" * [Node.js](node/ch-1.js) * [Perl](perl/ch-1.pl) * [Python](python/ch-1.py) -* [Ruby](ruby/ch-1.py) +* [Ruby](ruby/ch-1.rb) ### Blog @@ -66,5 +66,6 @@ Operation 2: replace 'u' with 'o' * [Node.js](node/ch-2.js) * [Perl](perl/ch-2.pl) * [Python](python/ch-2.py) +* [Ruby](ruby/ch-2.rb) ### Blog diff --git a/challenge-096/abigail/ruby/ch-2.rb b/challenge-096/abigail/ruby/ch-2.rb new file mode 100644 index 0000000000..65a57bd6d3 --- /dev/null +++ b/challenge-096/abigail/ruby/ch-2.rb @@ -0,0 +1,31 @@ +def LevenshteinDistance (first, second) + n = first . length + m = second . length + if n < m + first, second = second, first + n, m = m, n + end + distances = [] + for i in 0 .. n do + distances [i] = [] + for j in 0 .. m do + distances [i] [j] = i == 0 || j == 0 ? i + j + : [distances [i - 1] [j] + 1, + distances [i] [j - 1] + 1, + distances [i - 1] [j - 1] + + (first [i - 1] == second [j - 1] ? 0 : 1)] . min + end + # + # Release memory + # + if i > 1 + distances [i - 1] = nil + end + end + return distances [n] [m] +end + +ARGF . each_line do |_| + words = (_ . split (/\s+/)) . grep (/\S/) + puts (LevenshteinDistance words [0], words [1]) +end -- cgit From a7e6309b32bacaac724e734572f4017a6da70448 Mon Sep 17 00:00:00 2001 From: Abigail Date: Tue, 19 Jan 2021 22:00:40 +0100 Subject: Deal with leading and trailing whitespace. --- challenge-096/abigail/node/ch-2.js | 3 ++- challenge-096/abigail/t/ctest.ini | 5 +++++ challenge-096/abigail/t/input-2-3 | 1 + challenge-096/abigail/t/output-2-3.exp | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 challenge-096/abigail/t/input-2-3 create mode 100644 challenge-096/abigail/t/output-2-3.exp diff --git a/challenge-096/abigail/node/ch-2.js b/challenge-096/abigail/node/ch-2.js index 03f423b2ec..8423ab96b8 100644 --- a/challenge-096/abigail/node/ch-2.js +++ b/challenge-096/abigail/node/ch-2.js @@ -6,7 +6,8 @@ . toString () // Turn it into a string. . split ("\n") // Split on newlines. . filter (_ => _ . length) // Filter out empty lines. -. map (_ => console . log (LevenshteinDistance (_ . split (/\s+/)))) +. map (_ => console . log (LevenshteinDistance (_ . trim () + . split (/\s+/)))) ; // diff --git a/challenge-096/abigail/t/ctest.ini b/challenge-096/abigail/t/ctest.ini index 99eb989ad5..5592956f87 100644 --- a/challenge-096/abigail/t/ctest.ini +++ b/challenge-096/abigail/t/ctest.ini @@ -2,7 +2,12 @@ 1-1 = Given examples 2-1 = Given examples 2-2 = Wikipedia example +2-3 = Extra whitespace [1-1] trim = 0 + + +[2-3] +trim = 0 diff --git a/challenge-096/abigail/t/input-2-3 b/challenge-096/abigail/t/input-2-3 new file mode 100644 index 0000000000..80a194e95c --- /dev/null +++ b/challenge-096/abigail/t/input-2-3 @@ -0,0 +1 @@ + hello world diff --git a/challenge-096/abigail/t/output-2-3.exp b/challenge-096/abigail/t/output-2-3.exp new file mode 100644 index 0000000000..b8626c4cff --- /dev/null +++ b/challenge-096/abigail/t/output-2-3.exp @@ -0,0 +1 @@ +4 -- cgit From 053b0ef31a9cddae0cbd792ad539b2d68876538c Mon Sep 17 00:00:00 2001 From: Abigail Date: Tue, 19 Jan 2021 22:01:14 +0100 Subject: lua/ch-2.lua: Save some memory. --- challenge-096/abigail/lua/ch-2.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/challenge-096/abigail/lua/ch-2.lua b/challenge-096/abigail/lua/ch-2.lua index bb1b042b19..162f06eef0 100644 --- a/challenge-096/abigail/lua/ch-2.lua +++ b/challenge-096/abigail/lua/ch-2.lua @@ -33,6 +33,16 @@ function LevenshteinDistance (first, second) ) end end + + -- + -- We only need the previous row, so we can return the + -- memory of rows before that. This reduces the memory + -- usage from O (n * m) to O (min (n, m)) + -- + if i > 0 + then + distances [i - 1] = nil + end end return distances [n] [m] end -- cgit