我需要为要添加/组合到集合的新元素提供验证规则。 此规则将与集合中已存在的元素进行特定比较。
E.g。如果我的集合是一个有序集合,我不仅需要被conj接受的唯一元素,而且在某些其他特定情况下它们应该是唯一的:)
我的具体案例如下(不要批评我的例子:)它远非现实):
我有一组山脊(“山脉中的山脉”)作为他们在不同时间“偷看”的向量:)
E.g。
很多年前,山上有一个山脊:#{[1 0 2 0]}
很多年前,还有一个山脊增长:#{[1 0 2 0] [2 0 1 0]}
现在......我想允许只添加以下规则可接受的脊:
例如,在我们的上一个案例中#{[1 0 2 0][2 0 1 0]}
,
有效的脊是:[0 0 0 1][0 1 0 0][0 1 0 1][3 0 1 0] [1 0 3 0] [1 1 2 0] [2 0 1 1] [2 1 1 0]
等......
无效的山脊是:[1 0 1 0] [0 0 1 0]
等......
简而言之,我们只接受“至少在某个地方”更高层的山脊:)
问题是: 在clojure中实现此类验证的更好方法是什么?
if
和验证功能?答案 0 :(得分:0)
创建一个新的集合类型有点乏味但是(?)正确的解决方案(不要忘记实现读/打印,标签文字可能有帮助)。
在每个if
之前执行conj
不是最理想的,因为为了提高效率,您可能需要在集合中维护一些属性:在您的示例中,您可能希望保持每个位置的最小高度向量(从而允许决定是否在O(1)中添加项而不是O(n))。
您可以做的最少的是conj-ridge
功能:
(defn conj-ridge [[ridges min-heights :as ridges-set] ridge]
(if (= (map max min-heights ridge) min-heights)
ridges-set
[(conj ridges ridges) (map min min-heights ridge)]))
答案 1 :(得分:0)
您可以使用前置条件:
(defn higher-peak? [old-ridge new-ridge]
(some #(> (new-ridge %) (old-ridge %))
(range (count old-ridge))))
(defn conj-ridge [ridges ridge]
{:pre [(some #(higher-peak? % ridge) ridges)]}
(conj ridges ridge))
每当您尝试使用conj-ridge
添加没有更高峰的脊时,这将抛出AssertionError。如果您不想要错误,可以编写一个更高阶的函数,将conj-ridge
/ try
块中的catch
调用包装起来:
(defn conj-ridge-if-valid [ridges ridge]
(try
(conj-ridge ridges ridge)
(catch AssertionError e ridges)))