我发现在迭代时我经常需要以特殊的方式处理序列中的最后一个元素。例如,使用内置函数interpose
:
> (interpose ", " (range 4))
(0 ", " 1 ", " 2 ", " 3)
考虑这个问题的一种方法是:
我还发现在使用Seesaw构建Mig布局时我需要做一些特别的事情。例如,假设我想构建它:
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
| 4 | 5 | 6 |
+---+---+---+
| 7 | 8 | 9 |
+---+---+---+
其中每个数字是某个组件(例如按钮)。我可以通过制作整个面板“流”的Mig布局约束,然后将以下约束添加到每个组件来实现这一点:
请注意,上面可以这样说:
再次显示相同的“特殊最后元素”主题。
所以有两个问题:
是的,你可以创建辅助函数和宏,但我经常发现这一点,我倾向于认为它应该是上面的一个。换句话说 - 你遇到了相同类型的“问题”,你如何解决它们?
答案 0 :(得分:1)
你正在考虑序列的错误结束。 clojure中的所有序列(实际上是LISP)都是一系列元素序列的元素。
序列处理旨在让您为序列的第一个元素执行某些操作,然后将其余部分视为一个整体(可能是递归的)。实际上,clojure具有名为first
和rest
的函数来鼓励这种思维方式。
如@Rafal的评论所述,interpose可以是......
在clojure中你可以(几乎)用以下方式实现:
(defn interpose [s]
(cons (first s) (map #(str "," %) (rest s))))
core.clj中的实际实现建立在interleave
函数上,这个函数更复杂,因为它处理两个序列,但仍构建在第一个+ rest习惯用法上。
许多(大多数?)算法都适合这种思维方式。
答案 1 :(得分:1)
这里的大多数讨论都是基于你的假设,即所需的功能是“喜欢”。它在某些方面,但最大的区别是,为了优化插入的用途,它是懒惰的。
延迟函数从序列中获取元素,该序列可以是未知(即流)或甚至无限(即范围)长度。仅计算在根函数(即take)处产生值所需的元素。调用last和依赖于last的函数,如count,意味着原始序列需要完全遍历最后或计数才能实现。这就是sw1nn所警告的。
然而,在这种情况下,根据David的回答,元素的数量或最后一个元素的索引可能已经知道了。只要你可以在不使用count的情况下将它作为参数使用,你就可以很容易地创建这样的函数,甚至可以使它变得懒惰。
(def buttons [\a \b \c \d \e \f \g \h \i])
(defn partition-nth-but
[n b coll]
(map
(partial map second) ; remove index
(partition-by
#(and (integer? (/ (% 0) n)) (not= (% 0) b)) ; partition by index every nth but b
(map-indexed (fn [i v] [(inc i) v]) coll)))) ; index coll offset 1
=> (partition-nth-but 3 9 buttons)
((\a \b) (\c) (\d \e) (\f) (\g \h \i))
(def grow str)
(def grow-and-wrap (comp clojure.string/upper-case grow))
=> (map apply (cycle [grow grow-and-wrap]) (partition-nth-but 3 9 buttons))
("ab" "C" "de" "F" "ghi")
但是如果我们正在应用一系列函数,我们也可以循环通过正确的函数重复
(defn every-but-nth
[n rf nf]
(concat (repeat (dec n) rf) (repeat 1 nf)))
=> (apply concat
(every-but-nth 3
(every-but-nth 3 "grow" "grow-and")
(repeat 3 "grow")))
("grow" "grow" "grow-and" "grow" "grow" "grow-and" "grow" "grow" "grow")
=> (map
#(% %2)
(apply concat (every-but-nth
3
(every-but-nth 3 grow grow-and-wrap)
(repeat 3 grow)))
buttons)
("a" "b" "C" "d" "e" "F" "g" "h" "i")
答案 2 :(得分:0)
由于您知道输入的大小,例如 n ,因此只需对第一个 n-1 元素执行某些操作。这是初始 interpose 示例的最简单的解决方案。
在成长示例中,将 n-1 (或8)个元素包含在3和6处。然后添加 n (9)最后。
但是,您可能并不总是知道输入的大小。如果是这种情况,则可以通过省略第一个元素并仅对剩余元素进行操作来实现相同的结果。这是更普遍的情况,可能更接近于在使用clojure时如何鼓励你思考。