statler
statler

Reputation: 1381

How to destruct map with string keys AND parse - is there a neat(er) way?

I have a function in which I am destructing a map using :strs on the keys. I can easily destruct to strings (per below), and then individually parse the strings to integers (not shown), but I am looking for a neater way - preferably in the assignment using the :strs

Any advice would be appreciated - feel free to comment on the rest of the function too, I am always happy to learn.

(def t1 ["chr1" "85742012"  "." "G" "C" "2383.75"   "PASS"  "AF=0.993671;AO=157;DP=158;FAO=157;FDP=158;FR=.;FRO=1;FSAF=111;FSAR=46;FSRF=1;FSRR=0;FWDB=-0.0106874;FXX=0;HRUN=1;LEN=1;MLLD=115.26;QD=60.3481;RBI=0.0173573;REFB=-0.0963825;REVB=0.0136769;RO=1;SAF=111;SAR=46;SRF=1;SRR=0;SSEN=0;SSEP=0;SSSB=-0.00426731;STB=0.502242;STBP=0.593;TYPE=snp;VARB=0.000132517;OID=.;OPOS=85742012;OREF=G;OALT=C;OMAPALT=C"   "GT:GQ:DP:FDP:RO:FRO:AO:FAO:AF:SAR:SAF:SRF:SRR:FSAR:FSAF:FSRF:FSRR" "1/1:9:158:158:1:1:157:157:0.993671:46:111:1:0:46:111:1:0"])

(defn extract-vcf-single
[vcf-row]
(let [[chrom posn id ref- alt- qual filt info dt-form-str dt-val-str] vcf-row
    dt-form (str/split dt-form-str #":")
    dt-val (str/split dt-val-str #":")
    dt (zipmap dt-form dt-val)
    {:strs [GT RO AO DP]} dt
    ;; R0, A0 and DP are all integers. Is there a neat way to parse them in the destruct? so I can do this?
    ;; LAF (if (> RO AO) (/ RO DP) (/ AO DP))
    ] {(str chrom "_" posn)[chrom posn GT DP]}))

The best I have been able to do is;

(defn extract-vcf-single
[vcf-row]
(let [[chrom posn id ref- alt- qual filt info dt-form-str dt-val-str] vcf-row
    dt-form (str/split dt-form-str #":")
    dt-val (str/split dt-val-str #":")
    dt (zipmap dt-form dt-val)
    {:strs [GT RO AO DP]} dt
    [ROi AOi DPi] (map #(Integer. %) [RO AO DP])
    LAF (if (> ROi AOi) (/ ROi DPi) (/ AOi DPi))
    ] {(str chrom "_" posn)[chrom posn GT DPi LAF]}))

Upvotes: 1

Views: 349

Answers (1)

ponzao
ponzao

Reputation: 20934

I would consider creating a function that applies a function on specific values in a map, something like this:

(defn multi-update
  [m ks f]
  (reduce (fn [acc k]
            (update-in acc [k] f))
          m
          ks))

After which you can first parse specific values into integers and then do the actual destructuring:

(let [{:strs [GT RO]} (multi-update {"GT" "2"
                                     "FOOBAR" "BAZ"
                                     "RO" "6"}
                                    ["GT" "RO"]
                                    #(Integer/parseInt %))]
  [GT RO])
;=> [2 6]

Upvotes: 2

Related Questions