Reputation: 2754
I am trying to pass the (lazy) sequence returned from a map operation to another map operation, so that I can look up elements in the first sequence. The code is parsing some football fixtures from a text file (in row/column format), cleaning it up, and then returning a map.
Here is the code:
(ns fixtures.test.lazytest
(:require [clojure.string :as str])
(:use [clojure.test]))
(defn- column-map
"Produce map with column labels given raw data, return nil if not enough columns"
[cols]
(let [trimmed-cols (map str/trim cols)
column-names {0 :fixture-type, 1 :division, 2 :home-team, 4 :away-team}]
(if (> (count cols) (apply max (keys column-names)))
(zipmap (vals column-names) (map trimmed-cols (keys column-names)))
nil)))
(deftest test-mapping
(let [cols '["L" " Premier " " Chelsea " "v" "\tArsenal "]
fixture (column-map cols)]
(is (= "Arsenal" (fixture :away-team)))
(is (= "Chelsea" (fixture :home-team)))
(is (= "Premier" (fixture :division)))
(is (= "L" (fixture :fixture-type)))
)
)
(run-tests 'fixtures.test.lazytest)
The approach I'm taking is:
The problem is, using the trimmed-cols in zipmap causes
java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to clojure.lang.IFn
I think I know why this is happening ... as trimmed-cols is a LazySeq, the map called from zipmap is objecting to receiving a non-function as its first argument.
To fix this I can change the let to:
trimmed-cols (vec (map str/trim cols))
But this doesn't feel like the "best" option.
So:
(I hesitate to ask for an idiomatic solution, but imagine somewhere there must be a generally accepted way of doing this.)
Upvotes: 2
Views: 4103
Reputation: 3859
I am not entirely sure what you're after, but I can see why your code fails - like you said, trimmed-cols
is not a function. Wouldn't this simply work?
I'm using :_dummy
keys for columns that should be skipped. You can use as many as you like in the column-names
vector: zipmap
will merge them into one, which is removed by dissoc
.
(defn- column-map
"Produce map with column labels given raw data, return nil if not enough columns"
[cols]
(let [trimmed-cols (map str/trim cols)
column-names [:fixture-type :division :home-team :_dummy :away-team]]
(if (>= (count cols) (count column-names))
(dissoc (zipmap column-names trimmed-cols) :_dummy)
nil)))
(column-map ["L" " Premier " " Chelsea " "v" "\tArsenal "])
; => {:away-team "Arsenal", :home-team "Chelsea", :division "Premier", :fixture-type "L"}
Upvotes: 3