Created
September 10, 2015 21:57
-
-
Save RyanGough/d8793ab5425644c340cf to your computer and use it in GitHub Desktop.
checkout kata in clojure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns checkout.core-test | |
(:require [clojure.test :refer :all] | |
[checkout.core :refer :all])) | |
(deftest single-item | |
(testing "scannng a single A item gives price 50" | |
(is (= 50 (scan ["A"]))))) | |
(deftest different-item | |
(testing "scannng a single B item gives price 30" | |
(is (= 30 (scan ["B"]))))) | |
(deftest two-items | |
(testing "scannng two items gives sum of prices" | |
(is (= 80 (scan ["B" "A"]))))) | |
(deftest multi-buy-discount | |
(testing "price of 3 As is 120" | |
(is (= 120 (scan ["A" "A" "A"]))))) | |
;; tests for helpers | |
(deftest test-count-items | |
(testing "count items of each type" | |
(is (= {"A" 3 "B" 2} (count-items ["A" "A" "A" "B" "B"]))))) | |
(deftest test-count-discounts | |
(testing "calc number of discounts to apply" | |
(is (= {"A" 1} (count-discounts {"A" 5 "B" 2}))))) | |
(deftest test-full-price | |
(testing "calc number of full price items in basket" | |
(is (= {"A" 2} (count-full-price {"A" 5}))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns checkout.core | |
(:use clojure.test)) | |
(def prices {"A" 50 "B" 30}) | |
(def discounts {"A" {:amount 3 :price 120} }) | |
(defn count-items | |
"convert basket to a 'tally' (map from item type to number of that type)" | |
[basket] | |
(into | |
(hash-map) | |
(map | |
(fn | |
[[key val]] | |
[key (count val)]) | |
(group-by identity basket)))) | |
(defn tally-items-with-discounts | |
"filter a tally to just those items with discounts" | |
[tally] | |
(into | |
(hash-map) | |
(filter | |
(fn | |
[[key val]] | |
(contains? discounts key)) | |
tally))) | |
(defn count-discounts | |
"map a tally to a map from items to number of applicable discounts" | |
[tally] | |
(into | |
(hash-map) | |
(map | |
(fn | |
[[key val]] | |
[key (quot val ((discounts key) :amount))]) | |
(tally-items-with-discounts tally)))) | |
(defn count-full-price | |
"map a tally to a map from items to a count of full price items to be paid for" | |
[tally] | |
(into | |
(hash-map) | |
(map | |
(fn | |
[[key val]] | |
[key (mod val ((get discounts key {:amount (+ val 1)}) :amount))]) | |
tally))) | |
(defn acc-discount-price | |
[acc [key val]] | |
(+ (* ((discounts key) :price) val) acc)) | |
(defn acc-full-price | |
[acc [key val]] | |
(+ (* (prices key) val) acc)) | |
(defn cost-items | |
"return the cost of items or discounts given a costing function" | |
[things-to-cost costing-fun] | |
(reduce | |
costing-fun | |
0 | |
things-to-cost)) | |
(defn scan | |
"Returns total price for a basket of items" | |
[basket] | |
(+ | |
(cost-items (count-full-price (count-items basket)) acc-full-price) | |
(cost-items (count-discounts (count-items basket)) acc-discount-price))) | |
I guess i could write a little wrapper around map called hash-map-map
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
There must be something i can do about having to use "(into(hash-map)..." everywhere