如何生成在Clojure中编写的循环中循环的循环序列

时间:2015-12-03 19:53:50

标签: clojure

为了计划晚餐菜单,用户希望轮换3天肉,然后一个素食主菜。肉类轮换是牛肉,鸡肉,鱼肉,猪肉。蔬菜旋转搅拌然后豆腐。是否有比我下面的更好(更优雅,更简洁或可读)的方式来生成膳食序列?

(defn menu [n] (let [meat (cycle '[:beef :chicken :fish :pork])
                     veg (cycle '[:stirfry :tofu])]
                 (take n (mapcat seq (interleave (partition 3 meat) (partition 1 veg))))))

2 个答案:

答案 0 :(得分:1)

这个更短,更容易阅读我猜(并且可能更快):

(defn menu [n]
  (let [meat (cycle '[:beef :chicken :fish :pork])
        veg (cycle '[:stirfry :tofu])]
    (take n (rest (mapcat conj (partition 3 meat) veg)))))

在repl中:

user> (menu 10)
(:beef :chicken :fish :tofu :pork :beef :chicken :stirfry :fish :pork)

因为mapcat可以进行多次收集,所以会做

(conj (:beef :chicken :fish) :stirfry)

(conj (:pork :beef :chicken) :tofu)依此类推

你只需要删除第一个值,因为带有列表的conj会在开头添加一个元素。

如果可以从蔬菜餐开始,那么您也可能会丢失rest,使其缩短。

(take n (mapcat conj (partition 3 meat) veg))

答案 1 :(得分:0)

我很想概括这个问题:

  • 接受任意比例交错的任意数量的主菜。
  • 生成整个延迟序列,让客户端剪辑为 许多是必要的。

您可以提供数据作为备用数量和序列的菜肴。对于你的例子,我们有

(def dishes [3 [:beef :chicken :fish :pork]
             1 [:stirfry :tofu]])

我们可以调整您的解决方案,以产生无尽的懒惰菜肴序列:

(defn rotate [nlist-pairs]
  (let [pairs (partition 2 nlist-pairs)
        sources (map (fn [[n xs]] (partition n (cycle xs)))
                     pairs)]
    (apply concat (apply interleave sources))))

获得前十名......

(take 10 (rotate dishes))
;(:beef :chicken :fish :stirfry :pork :beef :chicken :tofu :fish :pork)