你如何编写一个函数来记住它在 clojure 中的先前输入
How do you write a function that remembers it's previous input in clojure
所以我在阅读 SO 时遇到了一个学生问题,该问题涉及找到最长的 char 序列,而下一个符号出现在当前符号之后。例如给定一个 "abzbac" 的字符串,输出将是 "abz"。这似乎是一个相当普遍的学习任务。输入为 increasing/decreasing 时取。所以我知道如何以命令的方式做到这一点。您迭代跟踪索引,查看当前索引和下一个索引是否通过谓词。我不知道如何以实用的方式做到这一点。我唯一的猜测是你必须构建一个函数来跟踪之前的输入,并且是一个谓词。在 python 我认为它应该是这样的。
def passTheTest(x):
def current(y):
temp = y == x # or w/e your comparison is
x = y # saves state for the next go around
return temp
你会如何在 clojure 中编写这个函数?
您可以使用 reduce
:
(apply str (:max-coll
(reduce (fn [{:keys [max-coll coll]} e]
(let [coll' (if (>= 0 (compare (peek coll) e) )
(conj coll e)
[e])]
{:coll coll'
:max-coll (if (<= (count max-coll) (count coll'))
coll'
max-coll)}))
{:max-coll [] :coll []}
"abyzbac")))
我也会用reduce,但我觉得这样更清晰一些。
;; rebuild a string from a vector of char
(apply str
;; get run from [run acc]
(first
(reduce
(fn [[run acc] ele]
;; add to acc if ascending
(let [acc' (if (pos? (compare ele (peek acc)))
(conj acc ele)
[ele])
;; replace run if acc is longer
run' (max-key count run acc')]
[run' acc']))
[[] [Character/MAX_VALUE]]
"abzabczab")))
一般来说,您可以通过在函数调用之间保存状态来完成任何操作,也可以通过添加描述先前状态的参数来完成。不同之处在于,通过添加参数,您可以根据需要更灵活地做事,并且如果您可以假设状态不存储在函数中,代码更容易理解和调试。
这里有一些不同的方法。
首先让我们看看我们对序列是否升序感兴趣。这实际上并不是单个值的 属性,而是 值的顺序对 。因此,如果我们可以根据顺序对重新解决问题,那么在每个点我们 都有 我们需要的数据,没有状态。为了制作这些对,我们可以使用 partition
每次取 2 个值,但以 1 为步进。例如,(partition 2 1 "abzbac")
,给我们 ((\a \b) (\b \z) (\z \b) ...
现在我们通常的映射、过滤等再次起作用:
(defn longest-increasing [the-str]
(let [pairs (partition 2 1 the-str) ;;Divide the string into the sequential pairs
directioned (partition-by (comp neg? (partial apply compare)) pairs) ;;Group pairs by whether the second char is "higher" or "lower"
ascending (filter #(neg? (apply compare (first %))) directioned) ;Filter out any descending sequences
longest (apply (partial max-key count) ascending)] ;;take the longest sequence
(clojure.string/join (cons (ffirst longest) (map second longest))))) ;;Glue it back together.
所以我在阅读 SO 时遇到了一个学生问题,该问题涉及找到最长的 char 序列,而下一个符号出现在当前符号之后。例如给定一个 "abzbac" 的字符串,输出将是 "abz"。这似乎是一个相当普遍的学习任务。输入为 increasing/decreasing 时取。所以我知道如何以命令的方式做到这一点。您迭代跟踪索引,查看当前索引和下一个索引是否通过谓词。我不知道如何以实用的方式做到这一点。我唯一的猜测是你必须构建一个函数来跟踪之前的输入,并且是一个谓词。在 python 我认为它应该是这样的。
def passTheTest(x):
def current(y):
temp = y == x # or w/e your comparison is
x = y # saves state for the next go around
return temp
你会如何在 clojure 中编写这个函数?
您可以使用 reduce
:
(apply str (:max-coll
(reduce (fn [{:keys [max-coll coll]} e]
(let [coll' (if (>= 0 (compare (peek coll) e) )
(conj coll e)
[e])]
{:coll coll'
:max-coll (if (<= (count max-coll) (count coll'))
coll'
max-coll)}))
{:max-coll [] :coll []}
"abyzbac")))
我也会用reduce,但我觉得这样更清晰一些。
;; rebuild a string from a vector of char
(apply str
;; get run from [run acc]
(first
(reduce
(fn [[run acc] ele]
;; add to acc if ascending
(let [acc' (if (pos? (compare ele (peek acc)))
(conj acc ele)
[ele])
;; replace run if acc is longer
run' (max-key count run acc')]
[run' acc']))
[[] [Character/MAX_VALUE]]
"abzabczab")))
一般来说,您可以通过在函数调用之间保存状态来完成任何操作,也可以通过添加描述先前状态的参数来完成。不同之处在于,通过添加参数,您可以根据需要更灵活地做事,并且如果您可以假设状态不存储在函数中,代码更容易理解和调试。
这里有一些不同的方法。
首先让我们看看我们对序列是否升序感兴趣。这实际上并不是单个值的 属性,而是 值的顺序对 。因此,如果我们可以根据顺序对重新解决问题,那么在每个点我们 都有 我们需要的数据,没有状态。为了制作这些对,我们可以使用 partition
每次取 2 个值,但以 1 为步进。例如,(partition 2 1 "abzbac")
,给我们 ((\a \b) (\b \z) (\z \b) ...
现在我们通常的映射、过滤等再次起作用:
(defn longest-increasing [the-str]
(let [pairs (partition 2 1 the-str) ;;Divide the string into the sequential pairs
directioned (partition-by (comp neg? (partial apply compare)) pairs) ;;Group pairs by whether the second char is "higher" or "lower"
ascending (filter #(neg? (apply compare (first %))) directioned) ;Filter out any descending sequences
longest (apply (partial max-key count) ascending)] ;;take the longest sequence
(clojure.string/join (cons (ffirst longest) (map second longest))))) ;;Glue it back together.