【问题标题】:How to prevent Clojure exception: clojure.lang.LazySeq cannot be cast to clojure.lang.IFn如何防止 Clojure 异常:clojure.lang.LazySeq 不能强制转换为 clojure.lang.IFn
【发布时间】:2012-01-07 11:07:03
【问题描述】:

我正在尝试将从映射操作返回的(惰性)序列传递给另一个映射操作,以便我可以查找第一个序列中的元素。该代码正在从文本文件(行/列格式)中解析一些足球赛程,对其进行清理,然后返回地图。

代码如下:

(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,将列名关键字与其对应的列数据中的元素组合起来(注意,并非所有列都被使用)

问题是,在zipmap中使用trimmed-cols会导致

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

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

要解决这个问题,我可以将 let 更改为:

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

但这感觉不是“最佳”选项。

所以:

  1. 是否有一个很好的通用解决方案可以将映射操作的结果用作另一个映射的“函数”参数?
  2. 是否有更好的方法可以从原始值数据向量导出 {:value} 对的映射,其中未使用所有向量元素?

(我犹豫是否要惯用解决方案,但想象一下,一定有一种普遍接受的方式来做到这一点。)

【问题讨论】:

    标签: clojure lazy-sequences


    【解决方案1】:

    我不完全确定您的目标是什么,但我可以看到您的代码失败的原因 - 就像您说的,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"}
    

    【讨论】:

    • 很好......我喜欢您的解决方案如何简化 zipmap 调用,并且关键字名称可以清楚(呃)正在发生的事情,所以这解决了我问题的第二部分。在第一部分,使用 (vec ...) 将映射结果转换为向量允许将其作为函数访问(对于较小的列表大小应该可以)。
    猜你喜欢
    • 2015-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2017-04-06
    • 1970-01-01
    相关资源
    最近更新 更多