Clojure - 在向量中找到相同值的最长连胜及其索引

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)

lee*_*ski 5

这就是我的建议:

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)