如何捕获“行”号

时间:2012-05-03 22:25:03

标签: clojure

我的问题是如何捕获匹配发生的向量行的索引?在下面的代码中,我做错了什么?

我有一个向量载体

(def v1 [[44 2 3 4 5][1 6 7 5 10][11 12 13 14 15]])

列索引和比较值

(def cmp-val1 11)
(def col-idx 0)

我想返回比较返回true的行索引。如果col-idx = 0且cmp-val1 = 11,我应该看到(第一个row-num)返回2,它返回1.

(defn ret-match-row
    "Return the index of the row, in which the cmp-val is found.
     It is okay to increment 0."

    [in-seq cmp-val col-idx]

    (let [rn 0]
        (let [row-num
            (for [seq-row in-seq
                    :let [local-row-num (inc rn)]
                    :when (= cmp-val (nth seq-row col-idx nil))]

                local-row-num)]

            (first row-num))))

来自lein repl:

bene-csv.core=> (ret-match-row v1 cmp-val1 col-idx)
1

4 个答案:

答案 0 :(得分:3)

=> (defn ret-match-row
      [coll cmp idx]
      (keep-indexed (fn [i v] (if (= cmp (get v idx)) i)) coll))

=> (ret-match-row v1 11 0)
(2)

答案 1 :(得分:3)

一个灵活的答案来自将它分成三个不同的问题并组成它们。

  • 创建您寻找的数据
  • 找到你想要的数据
  • 介绍它的外观。

首先我们通过向行添加行号来对行进行编号

(map vector v1 (range))

然后过滤掉不包含所需数字的行:

(filter (fn [[data index]] (some #{11} data)) (map vector v1 (range)))
> ([[11 12 13 14 15] 2])

这里我使用的技巧集合是测试其输入以包含在集合中的函数,这允许它测试多个值:

(filter (fn [[data index]] (some #{11 44} data)) (map vector v1 (range)))
> ([[44 2 3 4 5] 0] [[11 12 13 14 15] 2])

然后,因为你只想知道匹配的位置,而不是我们过滤的匹配内容:

(map second (filter (fn [[data index]] (some #{11 44} data)) (map vector v1 (range))))
> (0 2)

<小时/> 为了将它包装成一个很好的函数,我们写出了以下步骤:

(defn with-row-numbers [col] (map vector col (range)))
(defn find-my-rows [rows goals] 
   (filter (fn [[data index]] (some (set goals) data)) rows)) 
(defn present-rows [rows] (map second rows))

然后撰写:

(defn ret-match-row [data rows]
  (-> data 
   (with-row-numbers) 
   (find-my-rows rows) 
   (present-rows)))

(ret-match-row v1 [11])
(2)
抱歉,我无法帮助它使用多种值,这是一种习惯。

(ret-match-row v1 [11 15 44])
> (0 2)

答案 2 :(得分:1)

可能有其他方法可以做你要求的事情,但你可以使用循环/重复来实现你所追求的迭代:

(defn ret-match-row [rows val col-idx]                                                                              
  (loop [[row & rows] rows                                                                                          
         pos 0]                                                                                                     
    (cond                                                                                                           
      (not row)                                                                                                     
      nil                                                                                                           
      (= val (nth row col-idx))                                                                                     
      pos                                                                                                           
      :not-found                                                                                                    
      (recur rows (inc pos)))))                                                                                     

(ret-match-row [[44 2 3 4 5]                                                                                        
                [1 6 7 8 10]                                                                                        
                [11 12 13 14 15]]                                                                                   
               11                                                                                                   
               0)                                                                                                   

;; => 2

你也遇到了Clojure的不变性 - (incn)实际上并没有修改rn。 loop / recur解决方案也使用inc,但它将inc的结果传递给循环的下一次迭代。

Clojure for(list comprehension)表单也将遍历序列中的所有值,从而产生一个新序列 - 这很可能不是你想要的。即使你让for循环做你想要的,它也会找到所有的匹配,而不仅仅是第一个。循环/重复示例在第一场比赛时停止。

答案 3 :(得分:0)

我的看法,使用 clojure.contrib.seq find-first,indexed:

(defn ret-match-row [rows val col-idx]
(first 
(find-first #(= val (nth (second %) col-idx))
(indexed rows))))