2012-05-03 74 views
4

我的問題是如何捕獲匹配發生的向量行的索引?在下面的代碼中,我做錯了什麼?如何捕獲「行」號碼

我有載體

(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,I應該看到(第一行-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 
+0

感謝您的答案。我明天會試一試。有趣的是,我已經看到更多的評論說循環..重複是非常低的水平,並使用序列,但循環..重複總是似乎是一個更合乎邏輯的方式來解決這樣的問題。不管怎樣,謝謝。 – octopusgrabbus

+0

loop/recur在這裏效果很好,因爲你依賴於索引,你必須儘可能地放棄索引(這可能需要改變數據建模​​方式)以利用Clojure的FP風格。 – cgrand

+0

@cgrand即使在這裏出色的答案,我基本上希望縮短解決方案,並循環..再發一次對我來說。設置的解決方案具有允許多重比較的優點,但是我必須放棄在我搜索的列中。對於獨特的數據庫密鑰來說沒問題,但我依賴用戶生成的保險報告,這些報告可能並可能包含「駕駛艙」錯誤的結果。 – octopusgrabbus

回答

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的永恆 - 在(INC RN)實際上並沒有修改rn。循環/循環解決方案也使用inc,但它將inc的結果傳遞給循環的下一次迭代。

Clojure's for(list comprehension)form也將遍歷序列中的所有值,產生一個新的序列 - 這很可能不是您想要的。即使你爲for循環做了你想要的,它也會找到所有的匹配,而不僅僅是第一個匹配。循環/重複示例在第一次匹配時停止。

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) 
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) 
+0

謝謝@Arthur Ulfeldt,這是一個很好的解決方案,但它失去了搜索欄。關鍵可能是,但不應該在另一列。 – octopusgrabbus

0

我取,使用 clojure.contrib.seq發現,第一,索引:

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