我想在向量中获取nil元素的索引,例如。 [1 nil 3 nil nil 4 3 nil] => [1 3 4 7]
(defn nil-indices [vec]
(vec (remove nil? (map
#(if (= (second %) nil) (first %))
(partition-all 2 (interleave (range (count vec)) vec)))))
)
运行此代码会导致
java.lang.IllegalArgumentException:键必须是整数 (NO_SOURCE_FILE:0)
如果我忽略围绕一切的(vec)调用,它似乎有效,但返回序列而不是向量。
谢谢!
答案 0 :(得分:4)
请改为尝试:
(defn nil-indices [v]
(vec (remove nil? (map
#(if (= (second %) nil) (first %))
(partition-all 2 (interleave (range (count v)) v))))))
Clojure是一个LISP-1:它有一个函数和数据的命名空间,所以当你调用(vec ...)
时,你试图将结果序列传递给数据参数,而不是标准库vec函数。
答案 1 :(得分:1)
请参阅问题的其他答案(您正在隐藏vec
),但请考虑使用更简单的方法。
map
可以接受多个参数,在这种情况下,它们作为附加参数传递给map函数,例如(map f c1 c2 ...)
调用(f (first c1) (first c2) ...)
等,直到其中一个序列参数用完为止。
这意味着您的(partition-all 2 (interleave ...))
是一种非常详细的说法(map list (range) v)
。还有一个函数map-indexed
可以执行相同的操作。但是,它只需要一个序列参数,因此(map-indexed f c1 c2)
不合法。
以下是使用map-indexed
,线程和nil?
重写您的函数的清晰度:
(defn nil-indices [v]
; Note: map fn called like (f range-item v-item)
; Not like (f (range-item v-item)) as in your code.
(->> (map-indexed #(when (nil? %2) %1) v) ;; like (map #(when ...) (range) v)
(remove nil?)
vec))
但是,您可以使用简化和reduce-kv
功能来执行此操作。此函数类似于reduce
,但减少函数接收三个参数而不是两个:累加器,集合中项目的键(向量索引,映射键),以及项目本身。使用reduce-kv
,您可以更清楚地重写此功能(并且它可能运行得更快,尤其是瞬态):
(defn nil-indices [v]
(reduce-kv #(if (nil? %3) (conj %1 %2) %1) [] v))