【问题标题】:partition a lazy sequence - after - a predicate truth test changes划分惰性序列 - 之后 - 谓词真值测试更改
【发布时间】:2016-02-11 11:42:07
【问题描述】:

考虑存储在惰性序列中的句子:每个单词都是一个条目,但标点符号属于单词:

("It's" "time" "when" "it's" "time!" "What" "did" "you" "say?" "Nothing!")

现在应该在句子中“分区”。我写了一个辅助函数 last-punctuated?,它检查最后一个字符是否是非字母字符。 (这个没问题)

想要的结果:

(("It's" "time" "when" "it's" "time!") ("What" "did" "you" "say?") ("Nothing!"))

一切都应该保持懒惰。不幸的是,我不能使用 partition-by:此函数在给定谓词更改的结果之前拆分 ,这意味着标点符号条目不会被解释为子序列中的最后一个条目。

【问题讨论】:

标签: clojure functional-programming clojurescript


【解决方案1】:

我建议使用lazy-seq。想不出比这更好的了(也许这不是最好的):

(defn parts [items pred]
  (lazy-seq
   (when (seq items)
     (let [[l r] (split-with (complement pred) items)]
       (cons (concat l (take 1 r))
             (parts (rest r) pred))))))

在回复中:

user> (let [items '("It's" "time" "when" "it's"
                    "time!" "What" "did" "you"
                    "say?" "Nothing!")]
        (parts items (comp #{\? \! \. \,} last)))

(("It's" "time" "when" "it's" "time!") ("What" "did" "you" "say?") ("Nothing!"))

user> (let [items '("what?" "It's" "time" "when" "it's"
                    "time!" "What" "did" "you"
                    "say?" "Nothing!")]
        (parts items (comp #{\? \! \. \,} last)))

(("what?") ("It's" "time" "when" "it's" "time!") ("What" "did" "you" "say?") ("Nothing!"))

user> (let [items '("what?" "It's" "time" "when" "it's"
                    "time!" "What" "did" "you"
                    "say?" "Nothing!")]
        (realized? (parts items (comp #{\? \! \. \,} last))))

false

更新:可能与iterate 相同的方法会更好。

(defn parts [items pred]
  (->> [nil items]
       (iterate (fn [[_ items]]
                  (let [[l r] (split-with (complement pred) items)]
                    [(concat l (take 1 r)) (rest r)])))
       rest
       (map first)
       (take-while seq)))

【讨论】:

  • 简单来说,我最喜欢第一个(lazy-seq)版本。对我来说,这很清楚,它没有开销,必须进行迭代:比如:用 nil 初始化,其余的/(首先映射)。问题是:为什么您认为迭代方法会更好?它与递归和堆栈跟踪有关吗? (如循环/递归)
【解决方案2】:

这个问题实际上可以通过生成一个包含“拆分标记”的新序列来轻松表达,然后根据不同的谓词执行partition-by。:

(def punctuation? #{\. \! \?})

(def words ["It's" "time" "when" "it's" "time!" "What" "did" "you" "say?" "Nothing!"])

(defn partition-sentences [ws]
  (->> ws
    (mapcat #(if (punctuation? (last %)) [% :br] [%]))
    (partition-by #(= :br %))
    (take-nth 2)))


(println (take 20 (partition-sentences (repeatedly #(rand-nth words))))

【讨论】:

  • 看起来不错..我现在无法深入研究它...但是,只是:你确定这到底还是懒惰吗?啊,还有:一个改进:有 mapcat 可以让扁平化消失。
  • 我已按照您的建议改为使用 mapcat。更新后的示例表明,这永远不会强制实现整个序列。
  • 感谢您的努力,我喜欢这种方法的创造性。它完美地工作。最后,我决定使用 leetwinski 建议的解决方案之一(迭代/惰性序列),因为我发现使用“塞子”有点太老套了,但这是个人喜好。
【解决方案3】:

当输入的大小与输出的大小不同时,答案通常是使用reduce

(defn last-word? [word]
  (assert word)
  (or (.endsWith word "!")
      (.endsWith word "?")))

(defn make-sentence [in]
  (reduce (fn [acc ele]
            (let [up-to-current-sentence (vec (butlast acc))
                  last-word-last-sentence (-> acc last last)
                  new-sentence? (when last-word-last-sentence (last-word? last-word-last-sentence))
                  current-sentence (vec (last acc))]
              (if new-sentence?
                (conj acc [ele])
                (conj up-to-current-sentence (conj current-sentence ele)))))
          [] in))

很遗憾,reduce 需要结束,因此无法使用惰性输入。有讨论here

【讨论】:

  • reduce 一点也不懒惰......所以我想这不是操作想要的东西。
  • 只是在考虑这个事实。正要查找 reduce 是否可以变得懒惰。你可能知道。 reduce 似乎是这个问题的“去”。很高兴知道它是否可以变得懒惰。
猜你喜欢
  • 2014-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-09
相关资源
最近更新 更多