如何验证/过滤要在clojure中汇总(添加)到集合的新元素

时间:2014-06-16 08:39:48

标签: validation collections clojure

我需要为要添加/组合到集合的新元素提供验证规则。 此规则将与集合中已存在的元素进行特定比较。

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和验证功能?
  • 使用一些可用的clojure功能?例如,您可以将自定义比较器添加到sorted-set-by。问题是 - 是否可以提供一些自定义的“验证规则”?有没有合适的clojure库?
  • 还有其他想法吗?

2 个答案:

答案 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)))