我有三个类似的函数,他们过滤一组与键(列)匹配的映射与其值,不区分大小写.
这是我想要干的原始代码:
;; gets a collection filtered by a column, exact match
(defn get-collection-by-equals [collection-name column-name column-value]
(filter #(= (string/lower-case (column-name %)) (string/lower-case column-value)) (cached-get-collection collection-name)))
;; gets a collection filtered by a column, with partial match, case-insensitive
(defn get-collection-by-like [collection-name column-name column-value]
(filter #(string/includes? (string/lower-case (column-name %)) (string/lower-case column-value)) (cached-get-collection collection-name)))
;; gets a collection filtered by a column, which starts with given value, case-insensitive
(defn get-collection-by-starts-with [collection-name column-name column-value]
(filter #(string/starts-with? (string/lower-case (column-name %)) (string/lower-case column-value)) (cached-get-collection collection-name)))
Run Code Online (Sandbox Code Playgroud)
您可以看到代码有多相似,我只是在每种情况下使用不同的匹配策略=,includes?和starts-with?.
我的第一次尝试如下:
;; returns a function which does a case-insensitive match between given column and value for the given map
(defn matching-fn [match-fn column-name column-value]
(fn [map] (match-fn (string/lower-case (column-name map)) (string/lower-case column-value))))
;; gets a collection filtered by a column, exact match
(defn get-collection-by-equals [collection-name column-name column-value]
(filter #((matching-fn = column-name column-value) %) (cached-get-collection collection-name)))
;; gets a collection filtered by a column, with partial match, case-insensitive
(defn get-collection-by-like [collection-name column-name column-value]
(filter #((matching-fn string/includes? column-name column-value) %) (cached-get-collection collection-name)))
;; gets a collection filtered by a column, which starts with given value, case-insensitive
(defn get-collection-by-starts-with [collection-name column-name column-value]
(filter #((matching-fn string/starts-with? column-name column-value) %) (cached-get-collection collection-name)))
Run Code Online (Sandbox Code Playgroud)
我不喜欢这个解决方案的可读性,并且我发现我只能传递匹配函数,而不是具有返回函数的函数,我想出了这个:
;; gets a collection filtered by a column, using the given function, case-insensitive
(defn get-collection-by-filter [collection-name filter-fn column-name column-value]
(filter #(filter-fn (string/lower-case (column-name %)) (string/lower-case column-value)) (cached-get-collection collection-name)))
;; gets a collection filtered by a column, exact match, case-insensitive
(defn get-collection-by-equals [collection-name column-name column-value]
(get-collection-by collection-name = column-name column-value))
;; gets a collection filtered by a column, with partial match, case-insensitive
(defn get-collection-by-like [collection-name column-name column-value]
(get-collection-by collection-name string/includes? column-name column-value))
;; gets a collection filtered by a column, which starts with given value, case-insensitive
(defn get-collection-by-starts-with [collection-name column-name column-value]
(get-collection-by collection-name string/starts-with? column-name column-value))
Run Code Online (Sandbox Code Playgroud)
这是惯用的Clojure,还有其他(更好的)解决方案吗?
使用宏似乎有点矫枉过正.
像许多OO模式一样,在函数式语言中,整个模式归结为"使用带参数的函数".除了变为新函数的小部分之外,提取除了作为该函数的参数而更改的部分.
(defn collection-comparator [cmp]
(fn [collection-name column-name column-value]
(let [lower-value (string/lower-case column-value)]
(filter #(cmp (string/lower-case (column-name %))
lower-value)
(cached-get-collection collection-name)))))
(def get-collection-by-equals (collection-comparator =))
(def get-collection-by-like (collection-comparator string/includes?))
(def get-collection-by-starts-with (collection-comparator string/starts-with?))
Run Code Online (Sandbox Code Playgroud)