1 indexing vector clojure find
在向量中,我想找到某个值的最长连续记录以及该连续记录的起始索引。
示例:(longest-streak-of 1 [0 0 1 1 1 0 1 0]) 应返回 {:cnt 3 :at 2}。我发现的两个解决方案对我来说似乎不是很笨拙 - 我仍在学习,所以请耐心等待。欢迎任何提供更优雅解决方案的答案。
这是我的第一次尝试:
(defn longest-streak-of
"Returns map with :cnt (highest count of successive n's) and :at (place in arr)"
[n arr]
(loop [arr arr streak 0 oldstreak 0 arrcnt 0 place 0]
(if (and (not-empty arr) (some #(= n %) arr))
(if (= (first arr) n)
(recur (rest arr) (+ streak 1) oldstreak (inc arrcnt) place)
(recur (rest arr) 0 (if (> streak oldstreak)
streak oldstreak)
(inc arrcnt) (if (> streak oldstreak)
(- arrcnt streak) place)))
(if (> streak oldstreak) {:cnt streak :at (- arrcnt streak)}
{:cnt oldstreak :at place}))))
Run Code Online (Sandbox Code Playgroud)
第二种解决方案,它使用 clojure.string,但比上面的要慢(我对两个函数都进行了计时,这需要两倍的时间)。我更喜欢这样的东西,希望不使用字符串库,因为我认为它更容易阅读和理解:
(ns lso.core
(:require [clojure.string :as s])
(:gen-class))
(defn lso2 [n arr]
(let [maxn (apply max (map count (filter #(= (first %) n) (partition-by #(= n %) arr))))]
{:cnt maxn :at (s/index-of (s/join "" arr) (s/join (repeat maxn (str n))))}))
Run Code Online (Sandbox Code Playgroud)
提前感谢您的任何见解!
阅读艾伦的回答后的新版本:
(defn lso3
;; This seems to be the best solution yet
[n arr]
(if (some #(= n %) arr)
(let [parts (partition-by #(= n %) arr)
maxn (apply max (map count (filter #(= (first %) n) parts)))]
(loop [parts parts idx 0]
(if-not (and (= maxn (count (first parts))) (= n (first (first parts))))
(recur (rest parts) (+ idx (count (first parts))))
{:cnt maxn :at idx})))
{:cnt 0 :at 0}))
Run Code Online (Sandbox Code Playgroud)
这就是我的建议:
user> (->> [0 0 1 1 1 0 1 0]
(map-indexed vector) ;; ([0 0] [1 0] [2 1] [3 1] [4 1] [5 0] [6 1] [7 0])
(partition-by second) ;; (([0 0] [1 0]) ([2 1] [3 1] [4 1]) ([5 0]) ([6 1]) ([7 0]))
(filter (comp #{1} second first)) ;; (([2 1] [3 1] [4 1]) ([6 1]))
(map (juxt ffirst count)) ;; ([2 3] [6 1])
(apply max-key second) ;; [2 3]
(zipmap [:at :cnt])) ;; {:at 2, :cnt 3}
;; {:at 2, :cnt 3}
Run Code Online (Sandbox Code Playgroud)
或将其包装在一个函数中:
(defn longest-run [item data]
(when (seq data) ;; to prevent exception on apply for empty data
(->> data
(map-indexed vector)
(partition-by second)
(filter (comp #{item} second first))
(map (juxt ffirst count))
(apply max-key second)
(zipmap [:at :cnt]))))
user> (longest-run 1 [1 1 1 2 2 1 2 2 2 2 2])
;;=> {:at 0, :cnt 3}
Run Code Online (Sandbox Code Playgroud)
更新
这将防止apply出现错误的空序列:
(defn longest-run [item data]
(some->> data
(map-indexed vector)
(partition-by second)
(filter (comp #{item} second first))
(map (juxt ffirst count))
seq
(apply max-key second)
(zipmap [:at :cnt])))
Run Code Online (Sandbox Code Playgroud)