Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Last active February 17, 2020 01:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericnormand/c831dc1bb89713751d0c7b402145dcbf to your computer and use it in GitHub Desktop.
Save ericnormand/c831dc1bb89713751d0c7b402145dcbf to your computer and use it in GitHub Desktop.

total price of a shopping list

I have a shopping list, represented as a vector. Inside the vector are hash maps for each item, which look like this:

{:item :bread 
 :quantity 1
 :price 3.50}

There is a 10% tax added to the sum.

Write a function that takes a shopping list and returns a map like this:

{:total-before-tax 75.40
 :tax 7.54
 :total-after-tax 82.94}
(def tax-rate 0.1)
(defn checkout [item-list]
(let [subtotal (->> item-list
(map #(* (:price %) (:quantity %)))
(reduce +))
tax (* subtotal tax-rate)]
{:total-before-tax subtotal
:tax tax
:total-after-tax (+ subtotal tax)}))
;; TESTS
;;
(deftest test-order-cost
(let [items [{:item :bread
:quantity 1
:price 3.50}
{:item :apple
:quantity 1
:price 1.00}]]
(is (= (checkout items) {:total-before-tax 4.50
:tax 0.45
:total-after-tax 4.95})))
(let [items [{:item :bread
:quantity 5
:price 3.50}
{:item :apple
:quantity 10
:price 1.00}]]
(is (= (checkout items) {:total-before-tax 27.50
:tax 2.75
:total-after-tax 30.25}))))
(ns clojure-experiments.purely-functional.puzzles.0364-shopping-list
"https://purelyfunctional.tv/issues/purelyfunctional-tv-newsletter-364-tip-seek-the-model-and-enshrine-it-in-code/"
(:require [clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest]))
;;; Challenge: total price of a shopping list
;;; shopping list is represented as a vector where items are hash maps like this:
{:item :bread
:quantity 1
:price 3.50}
;;; There's a 10% tax added to teh sum
;;; Write a function that takes a shopping list and returns a map like this:
{:total-before-tax 75.40
:tax 7.54
:total-after-tax 82.94}
(s/def ::item keyword?)
(s/def ::quantity pos-int?)
(s/def ::price (s/and decimal? pos?)) ;; to achieve accurate price arithmetic
(s/def ::shopping-item (s/keys :req-un [::item ::quantity ::price]))
(s/def ::shopping-list (s/coll-of ::shopping-item :min-count 1))
(s/def ::total-before-tax ::price)
(s/def ::tax ::price)
(s/def ::total-after-tax ::price)
(s/fdef total-price
:args (s/cat :shopping-list ::shopping-list)
:ret (s/keys :req-un [::total-before-tax ::tax ::total-after-tax]))
(defn total-price [shopping-list]
(let [total (reduce (fn [subtotal {:keys [price]}]
(+ subtotal price))
0
shopping-list)
tax (* (bigdec 0.10) total)
total-after-tax (+ total tax)]
{:total-before-tax total
:tax tax
:total-after-tax total-after-tax}))
(comment
(s/exercise ::shopping-list)
(def my-shopping-list [{:item :_/., :quantity 2, :price 2.0M}
{:item :*/C, :quantity 2, :price 1.0M}
{:item :p/_, :quantity 1, :price 3.0M}
{:item :y/K, :quantity 2, :price 0.75M}
{:item :./!, :quantity 1, :price 1.0M}
{:item :m/z, :quantity 2, :price 2.0M}
{:item :d/h, :quantity 2, :price 2.0M}
{:item :-/E, :quantity 1, :price 0.5M}
{:item :C/?, :quantity 2, :price 0.5M}])
(total-price my-shopping-list)
;; => {:total-before-tax 12.75M, :tax 1.275M, :total-after-tax 14.025M}
;; exercise to get results
(s/exercise-fn `total-price 2)
;; => ([([{:item :Z/f, :quantity 1, :price 0.5M}
;; {:item :./., :quantity 1, :price 2.0M}
;; {:item :!/+, :quantity 2, :price 2.0M}
;; {:item :_/x, :quantity 1, :price 1.5M}
;; {:item :-/., :quantity 2, :price 1.25M}
;; {:item :F/l, :quantity 2, :price 2.0M}
;; {:item :K/l, :quantity 2, :price 0.5M}
;; {:item :-/_, :quantity 1, :price 2.0M}
;; {:item :z/., :quantity 2, :price 2.0M}
;; {:item :*/!, :quantity 2, :price 0.5M}
;; {:item :I/g, :quantity 2, :price 0.5M}
;; {:item :_/X, :quantity 1, :price 0.5M}
;; {:item :C/+, :quantity 1, :price 1.0M}
;; {:item :./H, :quantity 1, :price 2.0M}
;; {:item :m/x, :quantity 1, :price 0.5M}
;; {:item :n/*, :quantity 1, :price 2.0M}
;; {:item :N/M, :quantity 1, :price 2.0M}])
;; {:total-before-tax 22.75M, :tax 2.275M, :total-after-tax 25.025M}]
;; [([{:item :U2/g9, :quantity 2, :price 3.0M}
;; {:item :SX/PU, :quantity 1, :price 3.75M}
;; {:item :_/P, :quantity 1, :price 0.5M}
;; {:item :_b/cf, :quantity 2, :price 0.5M}
;; {:item :e/aP, :quantity 1, :price 0.5M}
;; {:item :R/A0, :quantity 1, :price 2.0M}
;; {:item :e/f., :quantity 1, :price 3.0M}
;; {:item :an/Dz, :quantity 2, :price 2.0M}
;; {:item :cS/Q, :quantity 1, :price 0.5M}
;; {:item :zq/f., :quantity 2, :price 1.0M}
;; {:item :mO/C, :quantity 2, :price 2.0M}
;; {:item :_2/?, :quantity 1, :price 2.0M}
;; {:item :+/W, :quantity 2, :price 1.0M}
;; {:item :?/i, :quantity 1, :price 2.0M}
;; {:item :c/a, :quantity 2, :price 0.5M}
;; {:item :o+/WH, :quantity 2, :price 0.5M}])
;; {:total-before-tax 24.75M, :tax 2.475M, :total-after-tax 27.225M}])
;; run stest/check to make sure it works
(stest/check `total-price)
;;
)
(defn total-shopping-list [slist]
(let [tot (apply + (map #(* (:quantity %) (:price %)) slist))
tax (* 0.1 tot)]
{:total-before-tax tot
:tax tax
:total-after-tax (+ tot tax)}))
(def shoppinglist
[{:item :bread
:quantity 1
:price 3.50}
{:item :milk
:quantity 2
:price 1.50}])
(defn calculateprice [l]
(let [keymap (map #(select-keys % [:quantity :price]) l)
price (reduce + (map *
(map :quantity keymap)
(map :price keymap)))]
{:total-before-tax price
:tax (* price 0.1)
:total-after-tax (+ price (* price 0.1))}
))
;; I'm assuming the price is /per unit/
(def sample-input
[{:item :bread
:quantity 1
:price 3.50}
{:item :milk
:quantity 2
:price 2.50}
{:item :chocolate
:quantity 5
:price 3.00}])
(defn apply-tax [price]
(let [tax 0.1]
{:total-before-tax price
:tax (* tax price)
:total-after-tax (* (+ 1 tax) price)}))
(defn total-price-of-shopping-list [shopping-list]
(->> shopping-list
(map (fn [item]
(* (:price item)
(or (:quantity item) 1))))
(reduce +)
apply-tax))
(comment
(total-price-of-shopping-list sample-input)
;; => {:total-before-tax 23.5, :tax 2.35, :total-after-tax 25.85}
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment