如何防止Clojure异常:clojure.lang.LazySeq无法强制转换为clojure.lang.IFn

时间:2012-01-07 11:07:03

标签: clojure lazy-sequences

我正在尝试将从map操作返回的(lazy)序列传递给另一个map操作,以便我可以在第一个序列中查找元素。代码正在从文本文件(行/列格式)中解析一些足球装置,清理它,然后返回一张地图。

以下是代码:

(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)

我采取的方法是:

  1. 清理列数据的向量(删除前导/尾随空格)
  2. 使用zipmap,将列名称关键字与列数据中的相应元素组合在一起(请注意,并非所有列都已使用)
  3. 问题是,使用zipmap中的 trimmed-cols 会导致

      

    java.lang.ClassCastException:clojure.lang.LazySeq无法强制转换为clojure.lang.IFn

    我想我知道为什么会这样......因为 trimmed-cols 是一个LazySeq,从zipmap调用的地图反对接收一个非函数作为它的第一个参数。

    要解决此问题,我可以将更改为:

    trimmed-cols (vec (map str/trim cols))
    

    但这并不是“最佳”选择。

    所以:

    1. 将地图操作的结果用作另一个地图的“函数”参数是否有一个很好的通用解决方案?
    2. 是否有更好的方法从原始值数据向量中导出{:value}对映射,而不是所有向量元素都使用?
    3. (我在寻求一个惯用的解决方案时犹豫不决,但想象一下必须有一种普遍接受的方式来做这件事。)

1 个答案:

答案 0 :(得分:3)

我不完全确定你所追求的是什么,但我可以看到你的代码失败的原因 - 就像你说的那样,trimmed-cols不是一个功能。这不是简单的工作吗?

我正在使用:_dummy个键来表示应该跳过的列。您可以在column-names向量中使用任意多个:zipmap将它们合并为一个,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"}