diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2021-09-30 09:01:47 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-09-30 09:01:47 +0100 |
| commit | ee04772404150ab3d76e172bfb7d7c18980ad75b (patch) | |
| tree | c82cd78931798a81cff426f3749e2f0e2f00c5e5 | |
| parent | fc5584791aeeeb083954849a4b57d37c4d6edf5f (diff) | |
| parent | ea1fffc2c7a7762111128528607a2a8ffd9b42f3 (diff) | |
| download | perlweeklychallenge-club-ee04772404150ab3d76e172bfb7d7c18980ad75b.tar.gz perlweeklychallenge-club-ee04772404150ab3d76e172bfb7d7c18980ad75b.tar.bz2 perlweeklychallenge-club-ee04772404150ab3d76e172bfb7d7c18980ad75b.zip | |
Merge pull request #4944 from tylerw/tw/challenge-132
Challenge 132 in Clojure
8 files changed, 157 insertions, 14 deletions
diff --git a/challenge-132/tyler-wardhaugh/clojure/README.md b/challenge-132/tyler-wardhaugh/clojure/README.md index 064e23e11f..74b8669aa3 100644 --- a/challenge-132/tyler-wardhaugh/clojure/README.md +++ b/challenge-132/tyler-wardhaugh/clojure/README.md @@ -1,7 +1,7 @@ -# tw.weekly.c130 +# tw.weekly.c132 -The Weekly Challenge - #130 - Tyler Wardhaugh +The Weekly Challenge - #132 - Tyler Wardhaugh ## Usage @@ -9,7 +9,7 @@ Clojure ([installation instructions](https://clojure.org/guides/getting_started# Run the project directly (shows default output from both tasks): - $ clojure -M -m tw.weekly.c130.core + $ clojure -M -m tw.weekly.c132.core # ... or ... $ bb run both @@ -21,15 +21,13 @@ Run the project's tests (which are samples from the task descriptions): Run Task #1 with input - $ clojure -M -m tw.weekly.c130.t1 N - # ... or ... - $ bb run task-1 N + $ clojure -M -m tw.weekly.c132.t1 D Run Task #2 with input: - $ clojure -M -m tw.weekly.c130.t2 D S + $ clojure -M -m tw.weekly.c132.t2 H1 H2 I1 I2 # ... or ... - $ bb run task-2 D S + $ bb run task-2 H1 H2 I1 I2 View available tasks Babashka can run: diff --git a/challenge-132/tyler-wardhaugh/clojure/bb.edn b/challenge-132/tyler-wardhaugh/clojure/bb.edn index 4cd11817b8..a0e8b96a48 100644 --- a/challenge-132/tyler-wardhaugh/clojure/bb.edn +++ b/challenge-132/tyler-wardhaugh/clojure/bb.edn @@ -63,7 +63,9 @@ :task (run-task :t1 *command-line-args*)} task-1-bb {:doc "Run Task 1 (via Babashka)" - :task (run-task-bb :t1 *command-line-args*)} + :task (binding [*out* *err*] + (println "error: can't run Task 1 via Babashka because it depends on some incompatible libraries.") + (System/exit 1))} task-2 {:doc "Run Task 2 (via clojure)" :task (run-task :t2 *command-line-args*)} diff --git a/challenge-132/tyler-wardhaugh/clojure/deps.edn b/challenge-132/tyler-wardhaugh/clojure/deps.edn index 5b1400b27e..e821835450 100644 --- a/challenge-132/tyler-wardhaugh/clojure/deps.edn +++ b/challenge-132/tyler-wardhaugh/clojure/deps.edn @@ -1,5 +1,6 @@ {:paths ["src" "resources"] - :deps {org.clojure/clojure {:mvn/version "1.10.3"}} + :deps {org.clojure/clojure {:mvn/version "1.10.3"} + clojure.java-time/clojure.java-time {:mvn/version "0.3.3"}} :aliases {:test {:extra-paths ["test"] :extra-deps {org.clojure/test.check {:mvn/version "1.1.0"} diff --git a/challenge-132/tyler-wardhaugh/clojure/pom.xml b/challenge-132/tyler-wardhaugh/clojure/pom.xml index b1039ce744..ca7a3f1f2a 100644 --- a/challenge-132/tyler-wardhaugh/clojure/pom.xml +++ b/challenge-132/tyler-wardhaugh/clojure/pom.xml @@ -2,11 +2,11 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>tw.weekly</groupId> - <artifactId>tw.weekly.c131</artifactId> + <artifactId>tw.weekly.c132</artifactId> <version>0.1.0-SNAPSHOT</version> - <name>tw.weekly.c131</name> - <description>Challenge #131</description> - <url>https://github.com/tw.weekly/tw.weekly.c131</url> + <name>tw.weekly.c132</name> + <description>Challenge #132</description> + <url>https://github.com/tw.weekly/tw.weekly.c132</url> <licenses> <license> <name>Eclipse Public License</name> @@ -24,6 +24,11 @@ <artifactId>clojure</artifactId> <version>1.10.3</version> </dependency> + <dependency> + <groupId>clojure.java-time</groupId> + <artifactId>clojure.java-time</artifactId> + <version>0.3.3</version> + </dependency> </dependencies> <build> <sourceDirectory>src</sourceDirectory> diff --git a/challenge-132/tyler-wardhaugh/clojure/src/tw/weekly/c132/core.clj b/challenge-132/tyler-wardhaugh/clojure/src/tw/weekly/c132/core.clj new file mode 100644 index 0000000000..4115f99d9b --- /dev/null +++ b/challenge-132/tyler-wardhaugh/clojure/src/tw/weekly/c132/core.clj @@ -0,0 +1,12 @@ +(ns tw.weekly.c132.core + (:require [tw.weekly.c132.t1 :as t1]) + (:require [tw.weekly.c132.t2 :as t2]) + (:gen-class)) + +(defn -main + "Run all tasks" + [& _] + (println "Task #1:") + (t1/-main) + (println "\nTask #2:") + (t2/-main)) diff --git a/challenge-132/tyler-wardhaugh/clojure/src/tw/weekly/c132/t1.clj b/challenge-132/tyler-wardhaugh/clojure/src/tw/weekly/c132/t1.clj new file mode 100644 index 0000000000..b24255c143 --- /dev/null +++ b/challenge-132/tyler-wardhaugh/clojure/src/tw/weekly/c132/t1.clj @@ -0,0 +1,35 @@ +(ns tw.weekly.c132.t1 + (:require [java-time :as j] + [clojure.pprint :refer [cl-format]])) + +;;; +; Task description for TASK #1 › Mirror Dates +;;; +(def DEFAULT-TODAY "2021/09/22") +(def DEFAULT-INPUT ["2021/09/18" DEFAULT-TODAY]) +(def DATE-FORMAT "yyyy/MM/dd") + +(defn parse-date + [s] + (j/local-date DATE-FORMAT s)) + +(defn format-date + [d] + (-> (j/formatter DATE-FORMAT) + (j/format d))) + +(defn mirror-date + [origin today] + (let [delta (j/time-between :days origin today) + before (j/minus origin (j/days delta)) + after (j/plus today (j/days delta))] + (list before after))) + +(defn -main + "Run Task 1 with a given input N, defaulting to the first example from the + task description." + [& args] + (let [[origin today] (map parse-date (or args DEFAULT-INPUT))] + (->> (mirror-date origin today) + (map format-date) + (cl-format true "~{~a~^, ~}~%")))) diff --git a/challenge-132/tyler-wardhaugh/clojure/src/tw/weekly/c132/t2.clj b/challenge-132/tyler-wardhaugh/clojure/src/tw/weekly/c132/t2.clj new file mode 100644 index 0000000000..0f0930b838 --- /dev/null +++ b/challenge-132/tyler-wardhaugh/clojure/src/tw/weekly/c132/t2.clj @@ -0,0 +1,62 @@ +(ns tw.weekly.c132.t2 + (:require [clojure.edn :as edn] + [clojure.pprint :refer [cl-format]])) + +;;; +; Task description for TASK #2, Hash Join +;;; +(def MAXSIZE "The maximum number of build relations to process at one time." 3) +(def DEFAULT-INPUT + [[[20, "Alex" ] + [28, "Joe" ] + [38, "Mike" ] + [18, "Alex" ] + [25, "David" ] + [18, "Simon" ]] + [["Alex", "Stewart"] + ["Joe", "Root" ] + ["Mike", "Gatting"] + ["Joe", "Blog" ] + ["Alex", "Jones" ] + ["Simon","Duane" ]] + 1 + 0]) + +(defn butnth + "Returns all values except the one at index." + [coll index] + (keep-indexed (fn [i v] (when (not= i index) v)) coll)) + +;;; Classic Hash Join +;; Algorithm description: +; https://en.wikipedia.org/wiki/Hash_join#Classic_hash_join +;; Notes: +; - We proactively batch the smaller relation (build) into MAXSIZE chunks to +; ensure it can fit into memory. +; - Order of output relation is not guaranteed. +;;; +(defn hash-join + [a b a-index b-index] + (let [[build build-index probe probe-index] + (if (<= (count a) (count b)) + [a a-index b b-index] + [b b-index a a-index])] + (-> (comp + (partition-all MAXSIZE) + (map (fn [batch] (group-by #(nth % build-index) batch))) + (mapcat + (fn [build-map] + (keep (fn [row] + (when-let [ks (build-map (nth row probe-index))] + (map #(concat % (butnth row probe-index)) ks))) + probe))) + cat) + (sequence build)))) + +(defn -main + "Run Task 1 with a given input H1, H2, I1, and I2, defaulting to the first + example from the task description." + [& args] + (let [[H1 H2 I1 I2] (or (some->> args (map edn/read-string)) DEFAULT-INPUT)] + (->> (hash-join H1 H2 I1 I2) + (cl-format true "~:{~a, ~s, ~s~%~}")))) diff --git a/challenge-132/tyler-wardhaugh/clojure/test/tw/weekly/c132_test.clj b/challenge-132/tyler-wardhaugh/clojure/test/tw/weekly/c132_test.clj new file mode 100644 index 0000000000..00edee2c66 --- /dev/null +++ b/challenge-132/tyler-wardhaugh/clojure/test/tw/weekly/c132_test.clj @@ -0,0 +1,28 @@ +(ns tw.weekly.c132-test + (:require [clojure.test :refer [deftest is testing]] + [tw.weekly.c132.t1 :as t1] + [tw.weekly.c132.t2 :as t2])) + +(def today (t1/parse-date t1/DEFAULT-TODAY)) + +(deftest task-1 + (testing "Task 1, Mirror Dates" + (let [today (t1/parse-date t1/DEFAULT-TODAY)] + (is (= (map t1/parse-date ["2021/09/14" "2021/09/26"]) + (t1/mirror-date (t1/parse-date "2021/09/18") today))) + (is (= (map t1/parse-date ["1929/10/27" "2067/09/05"]) + (t1/mirror-date (t1/parse-date "1975/10/10") today))) + (is (= (map t1/parse-date ["1912/07/08" "2076/04/30"]) + (t1/mirror-date (t1/parse-date "1967/02/14") today)))))) + +(deftest task-2 + (testing "Task 2, Hash Join" + (is (= (set '((20 "Alex" "Stewart") + (18 "Alex" "Stewart") + (28 "Joe" "Root") + (38 "Mike" "Gatting") + (28 "Joe" "Blog") + (20 "Alex" "Jones") + (18 "Alex" "Jones") + (18 "Simon" "Duane"))) + (set (apply t2/hash-join t2/DEFAULT-INPUT)))))) |
