From 5420696444dbc5d70c64a97eb147d190c2b4fa1f Mon Sep 17 00:00:00 2001 From: Dmitry Pavlov Date: Thu, 25 May 2023 19:18:03 +0300 Subject: [PATCH 1/4] Homework4: first touches - menu actions 1-3, 6 --- otus-06/src/otus_06/homework.clj | 94 +++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/otus-06/src/otus_06/homework.clj b/otus-06/src/otus_06/homework.clj index d5d5228..edd4b58 100644 --- a/otus-06/src/otus_06/homework.clj +++ b/otus-06/src/otus_06/homework.clj @@ -1,4 +1,6 @@ -(ns otus-06.homework) +(ns otus-06.homework + (:require [clojure.java.io :as io] + [clojure.string :as str])) ;; Загрузить данные из трех файлов на диске. ;; Эти данные сформируют вашу базу данных о продажах. @@ -94,3 +96,93 @@ ;; Файлы находятся в папке otus-06/resources/homework + +;; *** Sales Menu *** +;; ------------------ +;; 1. Display Customer Table +;; 2. Display Product Table +;; 3. Display Sales Table +;; 4. Total Sales for Customer +;; 5. Total Count for Product +;; 6. Exit + +(defn display-rows + [rows] + (doseq [{id :id data :data} rows] + (printf "%s: %s\n" id data))) + +(defn read-simple-table + [name] + (let [raw-rows (->> (str "homework/" name ".txt") + io/resource + slurp + str/split-lines + (map #(str/split % #"\|"))) + rows (mapv + (fn [[id & data]] {:id id :data (vec data)}) + raw-rows) + index (zipmap + (map :id rows) + (range 0 (count rows)))] + {:rows rows :index index})) +(defn enrich-sales-rows + [sales-rows customers products] + (let [{customers-rows :rows customers-index :index} customers + {products-rows :rows products-index :index} products] + (mapv + (fn [{id :id [cid pid & other] :data}] + (let [c-idx (get customers-index cid) + p-idx (get products-index pid) + c-row (get customers-rows c-idx) + p-row (get products-rows p-idx) + c-name (get-in c-row [:data 0]) + p-name (get-in p-row [:data 0])] + {:id id :data (into [c-name p-name] other)})) sales-rows))) + +(defn read-sales-table [] + (let [customers (read-simple-table 'cust) + products (read-simple-table 'prod) + sales (read-simple-table 'sales) + sales-rows (enrich-sales-rows (:rows sales) customers products)] + (assoc sales :rows sales-rows))) + +(defn display-table + [reader] + (let [{rows :rows} (reader)] + (display-rows rows))) + +(defn display-customer-table [] + (display-table (partial read-simple-table 'cust))) + +(defn display-product-table [] + (display-table (partial read-simple-table 'prod))) + +(defn display-sales-table [] + (display-table read-sales-table)) + +(defn goodbye [] + (println "Goodbye") + (System/exit 0)) + +(def menu + [{:name "Display Customer Table" :action display-customer-table} + {:name "Display Product Table" :action display-product-table} + {:name "Display Sales Table" :action display-sales-table} + {:name "Total Sales for Customer"} + {:name "Total Count for Product"} + {:name "Exit" :action goodbye}]) + +(defn print-menu + [menu] + (let [n (count menu) + numeric-menu (map #(vector %1 %2) + (range 1 (inc n)) + menu)] + (doseq [[id {name :name}] numeric-menu] + (printf "%s. %s\n" id name)))) + +(defn execute-action + [menu-item-id menu] + (let [menu-item (nth menu (dec menu-item-id)) + {action :action} menu-item] + (action))) From f8ea5a0f37313d5b91024b0af3079d65c3756502 Mon Sep 17 00:00:00 2001 From: Dmitry Pavlov Date: Fri, 26 May 2023 10:16:31 +0300 Subject: [PATCH 2/4] Homework4: user interaction for choosing menu item --- otus-06/src/otus_06/homework.clj | 60 +++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/otus-06/src/otus_06/homework.clj b/otus-06/src/otus_06/homework.clj index edd4b58..7d73e2c 100644 --- a/otus-06/src/otus_06/homework.clj +++ b/otus-06/src/otus_06/homework.clj @@ -118,12 +118,12 @@ slurp str/split-lines (map #(str/split % #"\|"))) - rows (mapv - (fn [[id & data]] {:id id :data (vec data)}) - raw-rows) - index (zipmap - (map :id rows) - (range 0 (count rows)))] + rows (mapv + (fn [[id & data]] {:id id :data (vec data)}) + raw-rows) + index (zipmap + (map :id rows) + (range))] {:rows rows :index index})) (defn enrich-sales-rows [sales-rows customers products] @@ -131,18 +131,18 @@ {products-rows :rows products-index :index} products] (mapv (fn [{id :id [cid pid & other] :data}] - (let [c-idx (get customers-index cid) - p-idx (get products-index pid) - c-row (get customers-rows c-idx) - p-row (get products-rows p-idx) + (let [c-idx (get customers-index cid) + p-idx (get products-index pid) + c-row (get customers-rows c-idx) + p-row (get products-rows p-idx) c-name (get-in c-row [:data 0]) p-name (get-in p-row [:data 0])] {:id id :data (into [c-name p-name] other)})) sales-rows))) (defn read-sales-table [] - (let [customers (read-simple-table 'cust) - products (read-simple-table 'prod) - sales (read-simple-table 'sales) + (let [customers (read-simple-table 'cust) + products (read-simple-table 'prod) + sales (read-simple-table 'sales) sales-rows (enrich-sales-rows (:rows sales) customers products)] (assoc sales :rows sales-rows))) @@ -174,15 +174,33 @@ (defn print-menu [menu] - (let [n (count menu) - numeric-menu (map #(vector %1 %2) - (range 1 (inc n)) - menu)] - (doseq [[id {name :name}] numeric-menu] - (printf "%s. %s\n" id name)))) + (doseq [i (range 0 (count menu))] + (printf "%s. %s\n" (inc i) (get-in menu [i :name])))) (defn execute-action - [menu-item-id menu] - (let [menu-item (nth menu (dec menu-item-id)) + [menu menu-item-id] + (println menu-item-id) + (let [menu-item (get menu (dec menu-item-id)) {action :action} menu-item] (action))) + +(defn choose-menu-item-prompt + [menu] + (print-menu menu) + (println) + (println "Enter an option?") + (let [input (read-line) + parse-result (try + (let [menu-item-id (Integer/parseInt input)] + [menu-item-id (<= 1 menu-item-id (inc (count menu)))]) + (catch Exception _ [input false]))] + (when (false? (second parse-result)) + (println "Wrong menu option:" input "\n")) + parse-result)) + +(defn program-dialog-run + [menu] + (let [[id] (->> (repeatedly (partial choose-menu-item-prompt menu)) + (filter #(true? (second %))) + (first))] + (execute-action menu id))) From 2b8111cd9d5d8d871ab0f1b4cecfb0c2c36c06f0 Mon Sep 17 00:00:00 2001 From: Dmitry Pavlov Date: Sun, 28 May 2023 21:01:06 +0300 Subject: [PATCH 3/4] Homework4: display-total-sales-for-customer --- otus-06/src/otus_06/homework.clj | 83 ++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 20 deletions(-) diff --git a/otus-06/src/otus_06/homework.clj b/otus-06/src/otus_06/homework.clj index 7d73e2c..c59d9ee 100644 --- a/otus-06/src/otus_06/homework.clj +++ b/otus-06/src/otus_06/homework.clj @@ -1,6 +1,7 @@ (ns otus-06.homework (:require [clojure.java.io :as io] - [clojure.string :as str])) + [clojure.string :as str]) + (:gen-class)) ;; Загрузить данные из трех файлов на диске. ;; Эти данные сформируют вашу базу данных о продажах. @@ -111,9 +112,9 @@ (doseq [{id :id data :data} rows] (printf "%s: %s\n" id data))) -(defn read-simple-table - [name] - (let [raw-rows (->> (str "homework/" name ".txt") +(defn load-table-data + [table-name] + (let [raw-rows (->> (str "homework/" table-name ".txt") io/resource slurp str/split-lines @@ -125,8 +126,13 @@ (map :id rows) (range))] {:rows rows :index index})) + +(def read-cust-table (partial load-table-data 'cust)) +(def read-prod-table (partial load-table-data 'prod)) +(def read-sales-table (partial load-table-data 'sales)) + (defn enrich-sales-rows - [sales-rows customers products] + [sales-rows customers products with-product-cost?] (let [{customers-rows :rows customers-index :index} customers {products-rows :rows products-index :index} products] (mapv @@ -136,29 +142,61 @@ c-row (get customers-rows c-idx) p-row (get products-rows p-idx) c-name (get-in c-row [:data 0]) - p-name (get-in p-row [:data 0])] - {:id id :data (into [c-name p-name] other)})) sales-rows))) - -(defn read-sales-table [] - (let [customers (read-simple-table 'cust) - products (read-simple-table 'prod) - sales (read-simple-table 'sales) - sales-rows (enrich-sales-rows (:rows sales) customers products)] + p-name (get-in p-row [:data 0]) + p-cost (get-in p-row [:data 1]) + data (if with-product-cost? + (into [c-name p-name p-cost] other) + (into [c-name p-name] other))] + {:id id :data data})) sales-rows))) + +(defn load-enriched-sales-table + [with-product-cost?] + (let [customers (read-cust-table) + products (read-prod-table) + sales (read-sales-table) + sales-rows (enrich-sales-rows (:rows sales) customers products with-product-cost?)] (assoc sales :rows sales-rows))) +(def read-enriched-sales-table (partial load-enriched-sales-table false)) +(def read-enriched-sales-table-with-product-cost (partial load-enriched-sales-table true)) + +(defn calc-total-sales-for-customer + [target-customer-name] + (let [{rows :rows} (read-enriched-sales-table-with-product-cost) + matched-rows (filter + #(= target-customer-name (get-in % [:data 0])) + rows) + total-sales (reduce + (fn [result {[_ _ cost-str quantity-str] :data}] + (let [cost (parse-double cost-str) + quantity (parse-long quantity-str)] + (+ result (* cost quantity)))) + 0.0 + matched-rows)] + total-sales)) + +(defn display-total-sales-for-customer + [] + (println "Enter customer name: ") + (let [customer-name (read-line)] + (->> customer-name + calc-total-sales-for-customer + (format "%s: $%.2f" customer-name) + println))) + (defn display-table [reader] (let [{rows :rows} (reader)] (display-rows rows))) (defn display-customer-table [] - (display-table (partial read-simple-table 'cust))) + (display-table read-cust-table)) (defn display-product-table [] - (display-table (partial read-simple-table 'prod))) + (display-table read-prod-table)) (defn display-sales-table [] - (display-table read-sales-table)) + (display-table read-enriched-sales-table)) (defn goodbye [] (println "Goodbye") @@ -168,18 +206,19 @@ [{:name "Display Customer Table" :action display-customer-table} {:name "Display Product Table" :action display-product-table} {:name "Display Sales Table" :action display-sales-table} - {:name "Total Sales for Customer"} + {:name "Total Sales for Customer" :action display-total-sales-for-customer} {:name "Total Count for Product"} {:name "Exit" :action goodbye}]) (defn print-menu [menu] + (println "*** Sales Menu ***") + (println "==================") (doseq [i (range 0 (count menu))] (printf "%s. %s\n" (inc i) (get-in menu [i :name])))) (defn execute-action [menu menu-item-id] - (println menu-item-id) (let [menu-item (get menu (dec menu-item-id)) {action :action} menu-item] (action))) @@ -198,9 +237,13 @@ (println "Wrong menu option:" input "\n")) parse-result)) -(defn program-dialog-run +(defn one-program-dialog-run [menu] (let [[id] (->> (repeatedly (partial choose-menu-item-prompt menu)) (filter #(true? (second %))) (first))] - (execute-action menu id))) + (execute-action menu id) + (println))) + +(defn -main [] + (while true (one-program-dialog-run menu))) From 121632df5ed828cf75e245ef7da1371709a29840 Mon Sep 17 00:00:00 2001 From: Dmitry Pavlov Date: Sun, 28 May 2023 23:07:45 +0300 Subject: [PATCH 4/4] Homework4: display-total-count-for-product --- otus-06/src/otus_06/homework.clj | 65 ++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/otus-06/src/otus_06/homework.clj b/otus-06/src/otus_06/homework.clj index c59d9ee..250f39e 100644 --- a/otus-06/src/otus_06/homework.clj +++ b/otus-06/src/otus_06/homework.clj @@ -160,29 +160,27 @@ (def read-enriched-sales-table (partial load-enriched-sales-table false)) (def read-enriched-sales-table-with-product-cost (partial load-enriched-sales-table true)) -(defn calc-total-sales-for-customer - [target-customer-name] - (let [{rows :rows} (read-enriched-sales-table-with-product-cost) - matched-rows (filter - #(= target-customer-name (get-in % [:data 0])) - rows) - total-sales (reduce - (fn [result {[_ _ cost-str quantity-str] :data}] - (let [cost (parse-double cost-str) - quantity (parse-long quantity-str)] - (+ result (* cost quantity)))) - 0.0 - matched-rows)] - total-sales)) +(defn calc-aggregation + [reader filter map reduce] + (let [{rows :rows} (reader) + aggregation (->> rows filter map reduce)] + aggregation)) -(defn display-total-sales-for-customer - [] - (println "Enter customer name: ") - (let [customer-name (read-line)] - (->> customer-name - calc-total-sales-for-customer - (format "%s: $%.2f" customer-name) - println))) +(defn calc-total-sales-for-customer + [customer-name] + (calc-aggregation + read-enriched-sales-table-with-product-cost + (partial filter #(= customer-name (get-in % [:data 0]))) + (partial map (fn [{[_ _ cost qnt] :data}] (* (parse-double cost) (parse-long qnt)))) + (partial reduce +))) + +(defn calc-total-count-for-product + [target-product-name] + (calc-aggregation + read-enriched-sales-table + (partial filter #(= target-product-name (get-in % [:data 1]))) + (partial map #(parse-long (get-in % [:data 2]))) + (partial reduce +))) (defn display-table [reader] @@ -198,6 +196,23 @@ (defn display-sales-table [] (display-table read-enriched-sales-table)) +(defn display-total-sales-for-customer + [] + (println "Enter customer name: ") + (let [customer-name (read-line)] + (->> customer-name + calc-total-sales-for-customer + (format "%s: $%.2f" customer-name) + println))) +(defn display-total-count-for-product + [] + (println "Enter product name: ") + (let [product-name (read-line)] + (->> product-name + calc-total-count-for-product + (format "%s: %d" product-name) + println))) + (defn goodbye [] (println "Goodbye") (System/exit 0)) @@ -207,7 +222,7 @@ {:name "Display Product Table" :action display-product-table} {:name "Display Sales Table" :action display-sales-table} {:name "Total Sales for Customer" :action display-total-sales-for-customer} - {:name "Total Count for Product"} + {:name "Total Count for Product" :action display-total-count-for-product} {:name "Exit" :action goodbye}]) (defn print-menu @@ -237,7 +252,7 @@ (println "Wrong menu option:" input "\n")) parse-result)) -(defn one-program-dialog-run +(defn execute-interactive-step [menu] (let [[id] (->> (repeatedly (partial choose-menu-item-prompt menu)) (filter #(true? (second %))) @@ -246,4 +261,4 @@ (println))) (defn -main [] - (while true (one-program-dialog-run menu))) + (while true (execute-interactive-step menu)))