Friday, February 19, 2016

Tiny job application problem solved in Clojure

Today Álvaro García passed me this problem to play with.

I solved it first in the REPL:

user=> (def text "epqiiqwdiwgyka_vsqtsujeqqicnhyivo_sigwasmkwgsih_akl_gtnkhgikgveidpmt
#_=> qybpxpnnpbxkwpisgjmdzgh_ojysbtsnsvxvuhguocp_qc_vouxqmg_cetlpmounxnvg
#_=> ldcpem_jodnmklgonocekdkjwkdoilajk_nxujykigsolengqmnqofpseqaamvpsooga
#_=> spyhoojennefwvljpvsqtgnceg_hsowqvycjkuxdtfbxfloewkphmvkftjlsasvwid_u
#_=> qcsgn_ypiqjytygiwyziqdjpxgpuunymadnclpdlmmulitsnqlwciotbmyfuummjynne
#_=> slnit_lpykdafkpydzkntbud_gigjgmu_uqjjmdzpwteodjpuzndxaqmsjdjjamnwoes
#_=> ajcffkaaoilpyydlkyxauagfcjbabapax_ndlgtpwnud_jpnkiokviqjhyopmjtgtbyo
#_=> iyfbjdhknimlah_cxfzwspqoscffiyvabtjjuc_liaqbcuomuytdqfy_xaixiiqqdpds
#_=> uuimzh_ywwcmodxhfxjplyixotjkeawauxltekptuieekpbokbanumffatbtiacnywhw
#_=> iqxebnosninpzfjmatvnyuspyeu_ziapvogconld_cxfcytkcp_bvsppz_dw_ndlpkhf
#_=> zdlxbo_vaflmailjvccgsuclyhojganjqxzmqflpze_hqhlul_ybaagtiuokbzaxhmec
#_=> olsptiexvvmhbdoelgmcffulcebhlyzd_m_qxkbfvnxykdudpxefsm_aqpqtnhxvswht
#_=> owqnbm_mgejjpyumm_mqbkiuulanbmzllmuqlfftmcxtybmijfuwaknefhekwgujpjqg
#_=> leu_sjtbszotcygiclkwcbmnvgsoqaqqkkgeaslhvfbtlgpnxgpzxp_vyjinlwwfbvtn
#_=> twogmnpxghabpxxgzlyirrrrrbbcrrrnbjpcrrrqykhrrrscarrrdnlxrrrrtudrrrr_
#_=> ntrbyrqlddbycypcccqongpgexhnabavrmebeofrxsnrilprveetxaranjyfmrisrewp
#_=> r_y_lgsrsedbn_rfrieusemhpfa_plkifjipvwaqvnenrrrzybsrbeurbhfrvrrzghr_
#_=> zpgiyrrrqsnnrrrbhvdrrrqkpdrraqvkeueszfpkj_fm_claw_oetbgurbdocb_rsnzr
#_=> cyvrvnrvaurbscimurtbriikrfdjlizribdjwkror_gnlzmshwccqcx_huaafbvituxo
#_=> ru_hohxwrrrhnbttrrriyyirrrnibricrxftrrrrvqvrrrrhjorehroldibsmquelwvy
#_=> jebkolbbnauompgqdhlbnsfbbdiudoeibwstdg_acsazhtgfufidogmyvtya_dfwihto
#_=> elucbtlcbaijlcuhfvhesgluiwttsdnqqshnoqumccyqtko_zh_fii_wlsspysdqdpad
#_=> fvfewlsojavmuaixyxpw_xcwxuatceosdqgmsbbagjmmblouvnywmqqakmmtuasfovol
#_=> _ogksdukwp_fkxuh_vfhuhfyfvvfqhqxecxsoctcqgpianhtnkbqlltwyhxotfksoewm
#_=> elxobjgwlyfaeoxsfohhguidoftbsainwovvglynsgjixon_nvuwflsfbca_xnnesvco
#_=> mceh_gigjxpllckcooagidcpbqxtnejlnlsccocuvcvge_fvjjbyqdkjceia_mkcvbzl
#_=> zwlxbdjihvpmdcvmssuvktwiqbeivtieol_bu_huumzmlxx_kd_vksmohgzl_fxwfdue
#_=> lqgfkgzxciwmuduozfbaxstxkwegescggkpxfpeenhb_whqhethcateqdvnxhpt__bja
#_=> _uiyxchmfkblmdwtyp_ktontmufw_isdflelsbgjizxvqbciuadfxxjaqbluofkgkkkh
#_=> jbvohisfla_cspbmuezqohnyijyimwgdeszutgnaoagbhku_wwdtylbbiyvbpoumgyid
#_=> w_xwg_fkogabccip_wouclnjcgdpwwxxvvvwkmmbgfeactbcksxqovqthtjfjghijwwh
#_=> ydfieyssbjtfqgqyjnmwfpesljmwapvbptucadontbobnspch_i_dxheklulncdsdnic
#_=> bnjjjedkaokw_ahcolvbcnmqtoakonpgzjufqlnn_uve_uumaufjasfvfcv_cbcuk_hd
#_=> zigkahchzfqjphjwcbjwmozyodhu_tsqtafwidgmc_snhhkleyvmzdtawdodzfmekuee
#_=> mnshz_xz")
#'user/text
user=> (def message "abcdefghijklmnopqrstuvwxyz_")
#'user/message
user=> (def frequecies-by-ch (frequencies text))
#'user/frequecies-by-ch
user=> (sort-by #(frequecies-by-ch %) message)
(\z \y \x \w \v \q \k \j \h \t \p \e \d \g \m \f \_ \s \r \a \l \u \c \o \n \i \b)
user=> (reverse (sort-by #(frequecies-by-ch %) message))
(\b \i \n \o \c \u \l \a \r \s \_ \f \m \g \d \e \p \t \h \j \k \q \v \w \x \y \z)
user=> (take-while
#_=> #(not= % \_)
#_=> (reverse (sort-by #(frequecies-by-ch %) message)))
(\b \i \n \o \c \u \l \a \r \s)
user=> (apply
#_=> str
#_=> (take-while
#_=> #(not= % \_)
#_=> (reverse (sort-by #(frequecies-by-ch %) message))))
"binoculars"
Then I collected all the code in the extract-info function:

user=> (defn extract-info [message text]
#_=> (let [frequecies-by-ch (frequencies text)]
#_=> (->> message
#_=> (sort-by #(frequecies-by-ch %))
#_=> reverse
#_=> (take-while #(not= % \_))
#_=> (apply str))))
#'user/extract-info
user=> (extract-info message text)
"binoculars"

Tuesday, February 9, 2016

Kata: Back to the Checkout in Clojure

I just did the Back to the Checkout kata.

These are the tests using Midje:

(ns back-checkout.core-test
(:require
[midje.sweet :refer :all]
[back-checkout.core :as checkout]))
(facts
"about the checkout system"
(let [prices-by-good {:A {:unit-price 50
:special-prices {3 130}}
:B {:unit-price 30
:special-prices {2 70}}
:C {:unit-price 100
:special-prices {3 200}}
:D {:unit-price 500
:special-prices {2 600}}
:E {:unit-price 80}}
price (partial checkout/price prices-by-good)]
(fact
"the price for zero goods is 0"
(price "") => 0)
(fact
"one unit of a good costs its unit price"
(price "A") => 50
(price "B") => 30)
(fact
"one unit of several goods cost the sum of their unit prices"
(price "AB") => 80)
(fact
"several units of a good cost the sum of its unit prices
if there is no special price for the given amount of goods"
(price "AA") => 100)
(fact
"several units of a good cost the special price
for the given amount of goods"
(price "AAA") => 130)
(fact
"several units of goods with and without special prices"
(price "AAABBBCCCDE") => 1000)))
and this is the resulting code:

(ns back-checkout.core)
(defn sku [c]
(keyword (str c)))
(defn unit-price [prices-by-good good-sku]
(get-in prices-by-good [good-sku :unit-price] 0))
(defn regular-price [prices-by-good [good-sku amount]]
(* amount (unit-price prices-by-good good-sku)))
(defn special-price [prices-by-good [good-sku amount]]
(get-in prices-by-good [good-sku :special-prices amount]))
(defn good-price [prices-by-good ordered-goods]
(or (special-price prices-by-good ordered-goods)
(regular-price prices-by-good ordered-goods)))
(defn price [prices-by-good goods]
(->> goods
(map sku)
frequencies
(map #(good-price prices-by-good %))
(reduce +)))
I did a mix of TDD and playing in the REPL to solve it.

You can check commits step by step here.

You can find all the code on GitHub.

Thursday, February 4, 2016

Interesting Talk: "Modificando el software de manera progresiva"

I've just watched this wonderful talk by Jaime Perera:

Interesting Talk: "Be a better developer (no code required) "

I've just watched this very interesting talk by Katherine Wu:

Interesting Talk: "Stop Building Services"

I've just watched this very interesting talk by Rachel Myers:

Kata: Wonderland Number in Clojure

I just redid the Wonderland Number kata from Carine Meier's Living Clojure book that we did this week at a Clojure Developers Barcelona event.

These are the tests using Midje:

(ns wonderland-number.finder-test
(:require [midje.sweet :refer :all]
[wonderland-number.finder :as finder]))
(defn same-digits-as [num]
(fn [multiple]
(= (set (str num)) (set (str multiple)))))
(defn digits-number [num]
(count (str num)))
(facts
"about Wonderland number"
(let [wondernum (finder/find-wonderland-number)]
(fact
"it has six digits"
(digits-number wondernum) => 6)
(fact
"it contains the same digits that its multiples by 2, 3, 4, 5 and 6"
(* 2 wondernum) => (same-digits-as wondernum)
(* 3 wondernum) => (same-digits-as wondernum)
(* 4 wondernum) => (same-digits-as wondernum)
(* 5 wondernum) => (same-digits-as wondernum)
(* 6 wondernum) => (same-digits-as wondernum))))
and this is the final code:

(ns wonderland-number.finder)
(def ^:private six-digts-nums
(range 100000 1000000))
(defn- digits [num]
(set (str num)))
(defn- same-digits? [num1 num2]
(= (digits num1) (digits num2)))
(defn- multiples [num]
(map #(* num %) [2 3 4 5 6]))
(defn- wonder? [num]
(every? (partial same-digits? num) (multiples num)))
(defn find-wonderland-number []
(first (filter wonder? six-digts-nums)))
I just played in the REPL to do it.

You can find all the code on GitHub.