Second mission
Navázal bych na post First Mission — napsal jsem další transformační skriptík pro stejný projekt. Opět šlo o to, přečíst vstupní soubor a na základě daných podmínek změnit některé hodnoty. Soubor obsahoval informaci o sdílených telefonech:
Tam, kde byla pro stejný telefon různá osobní čísla mělo dojít ke změně typu z PERSONAL na SHARED:
Měl jsem trochu obavy z “performance” (soubory mají 10k — 50k řádků), tak jsem to udělal na dva průchody — při prvním průchodu se do mapy vložily telefony, které měly více os. čísel a při druhém průchodu, kdy se všechny záznamy zapisovaly do upraveného souboru, se tyto záznamy měnily.
Skriptík je samozřejmě triviální, ale podstatné jsou věci, které jsem se přitom naučil — pořádně pracovat s Refs a transakcema (STM):
(def phones (ref {}))
(defn add-phone [phone pers-num]
(if (contains? @phones phone)
(if (contains? (@phones phone) pers-num)
(println "Duplicate record:" phone pers-num)
(dosync
(ref-set phones (update-in @phones [phone]
conj pers-num))))
(dosync
(ref-set phones (assoc @phones phone
#{pers-num})))))
(add-phone :123456789 :12)
(add-phone :123456789 :42)
(add-phone :123456789 :12)
(add-phone :123456790 :36)
(println @phones)
; Duplicate record: :123456789 :12
; {:123456790 #{:36}, :123456789 #{:12 :42}}
Další šikovná věc je “filrování mapy”:
(defn get-shared [m]
(select-keys m (for [[k v] m :when
(> (count v) 1)] k)))
(println
(get-shared
{:123456790 #{:36}, :123456789 #{:12 :42}})
; {:123456789 #{:12 :42}}
K tématu Refs bych se v budoucnu ještě rád vrátil — hned potom, co ze zásobníku vyndám a zpracuju sekvence.