哈希的Clojure向量中的值是否有所增加?

时间:2014-02-04 07:22:56

标签: vector hash clojure

新手Clojure问题提醒......

我有一个看起来像这样的Clojure矢量:

(def sample-data
  [{:date "2014-01-01" :value 5}
   {:date "2014-01-02" :value 7}
   {:date "2014-01-03" :value 6}
   {:date "2014-01-04" :value 7}
   {:date "2014-01-07" :value 11}])

实际上它比那要大得多,但是你得到了一般的想法...... - 它是一个单值的向量,每天收集一次。矢量将按日期顺序排序,但奇数缺失样本存在间隙。

我想创建一个在'sample-data'中使用:date的函数,并告诉我:该日期的值是否大于:前一日期的值。转角案例:

  • 如果前一天没有样品,那么我想回到收集样品的最后日期并与之比较:而不是
  • 如果没有:指定日期的值,那么我很乐意提出错误并在其他地方处理
  • 如果两个:值相等,我想返回false(因为它没有增加)

我想把这个函数称为例如。

(value-increased? sample-data {:date '2014-01-03'})

并获得一个布尔响应。在这种情况下,它将是错误的,因为2014-01-03(6)的值小于前一天的值(7)

提前致谢

4 个答案:

答案 0 :(得分:4)

您可以使用二进制搜索找到给定日期的索引,然后检查该索引处的条目和前一个条目。

或者,您可以使用mikera的timeline库,该库提供了一种数据结构,用于维护这类时间戳值的类似矢量的日志以及在此类日志上运行的各种函数:

(require '[mikera.timeline :as tl])

(def t
  (-> (tl/timeline)
      ;; (tl/log timestamp value)
      (tl/log 0 0)
      (tl/log 86400000 1)))

然后tl/seek允许您在给定时间之前找到最后一个条目的索引,而可以使用nth提取给定索引处的条目。

最后,clj-time对于指定时间非常有用(并且已经是时间轴的依赖关系):

(tl/log (tl/timeline) (clj-time.core/now) :foo)
;= #<Timeline [[#<Instant 2014-02-04T08:00:08.290Z> :foo]]>

答案 1 :(得分:2)

(defn has-value-increased?
  [sample searched-date]
  (reduce (fn [_ [{:keys prev-value :value} {:keys [value date]}]]
            (if (and (= date searched-date)
                     (< prev-value value))
              (reduced true)))
          nil
          (partition 2 1 sample)))

请注意,这可能是低效的,因为每次调用函数都可以遍历整个样本。根据实际应用程序,编写一个函数来收集一遍中值增加的所有日期并将其返回e肯定会更好。 G。作为一个集合,您可以在其中将其作为函数调用,以检查日期是否已增加。

以下是修改后的函数:

(defn collect-dates-with-increased-value
  [sample]
  (reduce (fn [acc [{prev-value :value} {:keys [date value]}]]
            (cond-> acc
              (< prev-value value) (conj date)))
          []
          (partition 2 1 sample)))

然后收集日期,e。 G。在REPL:

=> (def dates-with-increased-value (set (collect-dates-with-increased-value sample-data)))
=> dates-with-increased-value
#{"2014-01-02" "2014-01-04" "2014-01-07"} 
=> (dates-with-increased-value "2014-01-02")
"2014-01-02"
=> (dates-with-increased-value "2014-01-03")
nil 

答案 2 :(得分:1)

如果您尝试使用此代码,则可以对(第一个..)中的每一行进行注释,以查看哪个步骤可以执行哪些操作。

(->>
  sample-data
  (filter :value)
  (map #(assoc % :date (.parse (java.text.SimpleDateFormat. "yyyy-MM-dd") (:date %))))
                     ;parse date
  (sort-by :date)
  (partition 2 1)    ;partition the sequence into every two consecutive days that have a :date value
  (map (fn [[f s]]   ;destructure vector into first day f and second day s 
         (conj s [:in-order (< (:value f) (:value s))])))
                     ;compare days, return second date with compare boolean in in :in-order key 
  (remove :in-order) ;filter where :in-order is false
  first              ;take first false :in-order, and stop processing
)

答案 3 :(得分:1)

是否有理由不能使用有序集而不是向量?如果集合实际按日期排序,并且Clojure知道它,您可以使用get查找特定日期,或subseq / rsubseq查找某个目标附近的日期。那么你可以很容易地检查你想要的任何日期。