我正在编写 clojure 代码,我在循环中使用 case 语句,我希望每个数据都在一张地图中,下面是我编写的代码以及我在 print 语句中获得的所有数据我希望所有这些都在一张地图中
(defn formatGa4DimensionFilters [stringData]
(def abc {:orGroup {:expressions []}})
(doseq [semiFormat (str/split stringData #";")]
(if (str/includes? semiFormat ",")
(do (doseq [commaFormat (str/split semiFormat #",")]
(def filterSymbol (get-symbol-for-filter commaFormat))
(case filterSymbol
"=~" (let [[key value] (str/split commaFormat #"=~")]
(println {:filter {:fieldName key :stringFilter {:values value :matchType "PARTIAL_REGEXP"}}}))
"!~" (let [[key value] (str/split commaFormat #"!~")]
(println {:notExpression {:filter {:fieldName key :stringFilter {:values value :matchType "PARTIAL_REGEXP"}}}}))
"=@" (let [[key value] (str/split commaFormat #"=@")]
(println {:filter {:fieldName key :stringFilter {:values value :matchType "CONTAINS"}}}))
"!@" (let [[key value] (str/split commaFormat #"!@")]
(println {:notExpression {:filter {:fieldName key :stringFilter {:values value :matchType "CONTAINS"}}}}))
"==" (let [[key value] (str/split commaFormat #"==")]
(println {:filter {:fieldName key :stringFilter {:values value :matchType "EXACT"}}}))
"!=" (let [[key value] (str/split commaFormat #"!=")]
(println {:notExpression {:filter {:fieldName key :stringFilter {:values value :matchType "EXACT"}}}}))
(println "x is not defined"))))
(do (def symbolFilter2 (get-symbol-for-filter semiFormat))
(case symbolFilter2
"=~" (let [[key value] (str/split semiFormat #"=~")]
(println {:filter {:fieldName key :stringFilter {:values value :matchType "PARTIAL_REGEXP"}}}))
"!~" (let [[key value] (str/split semiFormat #"!~")]
(println {:notExpression {:filter {:fieldName key :stringFilter {:values value :matchType "PARTIAL_REGEXP"}}}}))
"=@" (let [[key value] (str/split semiFormat #"=@")]
(println {:filter {:fieldName key :stringFilter {:values value :matchType "CONTAINS"}}}))
"!@" (let [[key value] (str/split semiFormat #"!@")]
(println {:notExpression {:filter {:fieldName key :stringFilter {:values value :matchType "CONTAINS"}}}}))
"==" (let [[key value] (str/split semiFormat #"==")]
(println {:filter {:fieldName key :stringFilter {:values value :matchType "EXACT"}}}))
"!=" (let [[key value] (str/split semiFormat #"!=")]
(println {:notExpression {:filter {:fieldName key :stringFilter {:values value :matchType "EXACT"}}}}))
(println "x is not defined"))))))
(defn ga4DimensionFilters [semiFormat]
(for [commaFormat (str/split semiFormat #",")]
(def filterSymbol (get-symbol-for-filter commaFormat))
)
filterSymbol
)
(defn get-symbol-for-filter [string]
(doseq [ga4-filter-symbols ["=~","!~","=@","!@","==","!="]]
(def match-found (str/includes? string ga4-filter-symbols))
(if (boolean match-found)
(def filterMatch ga4-filter-symbols)))
filterMatch)
(def stringData "ga:city==San Jose,ga:city==Bengaluru;ga:country=~India;ga:country!~United States;ga:state==delhi,ga:state==goa")
(formatGa4DimensionFilters stringData)
当前打印数据
{:filter {:fieldName ga:city, :stringFilter {:values San Jose, :matchType EXACT}}}
{:filter {:fieldName ga:city, :stringFilter {:values Bengaluru, :matchType EXACT}}}
{:filter {:fieldName ga:country, :stringFilter {:values India, :matchType PARTIAL_REGEXP}}}
{:notExpression {:filter {:fieldName ga:country, :stringFilter {:values United States, :matchType PARTIAL_REGEXP}}}}
{:filter {:fieldName ga:state, :stringFilter {:values delhi, :matchType EXACT}}}
{:filter {:fieldName ga:state, :stringFilter {:values goa, :matchType EXACT}}}
nil
预期产出
{:expressions
{:filter {:fieldName ga:city, :stringFilter {:values San Jose, :matchType EXACT}}}
{:filter {:fieldName ga:city, :stringFilter {:values Bengaluru, :matchType EXACT}}}
{:filter {:fieldName ga:country, :stringFilter {:values India, :matchType PARTIAL_REGEXP}}}
{:notExpression {:filter {:fieldName ga:country, :stringFilter {:values United States, :matchType PARTIAL_REGEXP}}}}
{:filter {:fieldName ga:state, :stringFilter {:values delhi, :matchType EXACT}}}
{:filter {:fieldName ga:state, :stringFilter {:values goa, :matchType EXACT}}}
}
所有都应该在单个映射中 {:expressions ... }
过度使用 def 是代码中最明显的禁忌。上面的每一次使用都是错误的。
注意你的功能:
(defn get-symbol-for-filter [string]
(doseq [ga4-filter-symbols ["=~","!~","=@","!@","==","!="]]
(def match-found (str/includes? string ga4-filter-symbols))
(if (boolean match-found)
(def filterMatch ga4-filter-symbols)))
filterMatch)
可以替换为:
(defn get-symbol-for-filter [string]
(re-find #"=~|!=|=@|!@|==|!=" string))
我不确定我是否理解 prinln 的意图(输出或调试/开发?)以及“;”之间的区别和“,”分隔符(在上面的评论中提出)但您可以使用的解决方案可能是:
(defn get-filters [string-data]
(let [match-type->name {"==" "EXACT"
"=~" "PARTIAL_REGEXP"
"=@" "CONTAINS"
"!=" "EXACT"
"!~" "PARTIAL_REGEX"
"!@" "CONTAINS"}
notExpression? #(str/starts-with? % "!")
;; note this regex is (re-pattern (str "^(.*)(" (str/join "|" (keys matches)) ")(.*)$"))
re-key-type-value #"^(.*)(==|=~|=@|!=|!~|!@)(.*)$"]
(->>
(for [sub-str (str/split string-data #";|,")]
(if-let [[_ key match-type value] (re-matches re-key-type-value sub-str)]
(let [filter {:filter {:fieldName key :stringFilter {:values value :matchType (match-type->name match-type)}}}]
(if (notExpression? match-type)
{:notExpression filter}
filter))
(str "No Match for: " sub-str)))
(vec)
(assoc {} :expressions))))
看到“重新匹配”行执行多项任务(即找到匹配项并分离出您之前分别完成的键和值)
也许你想要这样的东西:
(ns match.type
(:require [clojure.string :as str]))
(def match-type {"=~" "PARTIAL_REGEXP"
"!~" "PARTIAL_REGEXP"
"=@" "CONTAINS"
"!@" "CONTAINS"
"==" "EXACT"
"!=" "EXACT"})
(defn is-in? [s & {:keys [m] :or {m match-type}}]
(str/includes? s (keys m)))
(defn get-filter [s]
(when (is-in? s :m match-type)
(let [[key value] (str/split s (re-pattern (str s)))]
{:fieldName key
:stringFilter {:values value
:matchType (match-type s "UNKNOWN")}})))
(defn format-ga4-dimension-filters [string-data]
(let [exps (->> (str/split string-data #";")
(mapcat #(if (str/includes? % ",")
(->> (str/split % #",")
(mapv get-filter))
[(get-filter %)])))]
{:orGroup {:expressions exps}}))
我在这里充分利用映射
match-type
。
例如它的键列表
(keys match-type)
被测试是否出现在 is-in?
.
与其到处写
(println ...)
,不如只返回值。最后在电话周围加上(println ...)
。
或者只是收集结果。 (将副作用与实际计算分开)。
一旦定义了一个映射,就可以将这个映射也用作一个 getter 函数。所以保存定义一个函数——甚至可以给出第三个值作为它的默认返回值——在我们的例子中是“未知”。
swap!
是一种非常命令式的方式 - 有时它会节省时间和内存。但在这里,它是多余的。我们可以直接构建结果图。不需要 swap!
和 update-in
.
所以我改用
let
表达式并在最后构造{:orGroup {:expressions exps}}
.
并且可以在使用可以返回要收集的各种元素的函数进行收集时使用
mapcat
。所以这里不需要命令式函数。
更明确的形式是:
(ns match.type
(:require [clojure.string :as str]))
(def match-type {"=~" "PARTIAL_REGEXP"
"!~" "PARTIAL_REGEXP"
"=@" "CONTAINS"
"!@" "CONTAINS"
"==" "EXACT"
"!=" "EXACT"})
(defn is-in? [s m]
(str/includes? s (keys m)))
(defn get-filter [s m]
(when (is-in? s m)
(let [[key value] (str/split s (re-pattern (str s)))]
{:fieldName key
:stringFilter {:values value
:matchType (m s "UNKNOWN")}})))
(defn format-ga4-dimension-filters [string-data m] ;; m is the map match-type
{:orGroup {:expressions
(mapcat #(if (str/includes? % ",")
(mapv (get-filter % m)
(str/split % #","))
[(get-filter % m)])
(str/split string-data #";"))}})
在这里,匹配类型映射被明确地赋予函数。 (参考透明度)。这些功能更容易测试。
在 case 循环中打印什么,我想在里面全部返回 该功能的一张地图(提到的预期输出)。
您可以对代码进行一些更改,使其以这种方式工作。然而,你最终会得到一个相当命令式的解决方案,这是好的,人们总是用其他语言(如 Java)编写这种代码,但不是惯用的 Clojure。总结变化:
let
而不是 def
.result
累积到一个初始化为 (atom [])
的原子中。println
替换emit
,emit
是一个累加结果的局部函数。{:expressions (deref result)}
.随着这些变化,我们最终得到
(defn formatGa4DimensionFilters [stringData]
(let [abc {:orGroup {:expressions []}}
result (atom [])
emit #(swap! result conj %)]
(doseq [semiFormat (str/split stringData #";")]
(if (str/includes? semiFormat ",")
(do (doseq [commaFormat (str/split semiFormat #",")]
(let [filterSymbol (get-symbol-for-filter commaFormat)]
(case filterSymbol
"=~" (let [[key value] (str/split commaFormat #"=~")]
(emit {:filter {:fieldName key :stringFilter {:values value :matchType "PARTIAL_REGEXP"}}}))
"!~" (let [[key value] (str/split commaFormat #"!~")]
(emit {:notExpression {:filter {:fieldName key :stringFilter {:values value :matchType "PARTIAL_REGEXP"}}}}))
"=@" (let [[key value] (str/split commaFormat #"=@")]
(emit {:filter {:fieldName key :stringFilter {:values value :matchType "CONTAINS"}}}))
"!@" (let [[key value] (str/split commaFormat #"!@")]
(emit {:notExpression {:filter {:fieldName key :stringFilter {:values value :matchType "CONTAINS"}}}}))
"==" (let [[key value] (str/split commaFormat #"==")]
(emit {:filter {:fieldName key :stringFilter {:values value :matchType "EXACT"}}}))
"!=" (let [[key value] (str/split commaFormat #"!=")]
(emit {:notExpression {:filter {:fieldName key :stringFilter {:values value :matchType "EXACT"}}}}))
(println "x is not defined")))))
(do (let [symbolFilter2 (get-symbol-for-filter semiFormat)]
(case symbolFilter2
"=~" (let [[key value] (str/split semiFormat #"=~")]
(emit {:filter {:fieldName key :stringFilter {:values value :matchType "PARTIAL_REGEXP"}}}))
"!~" (let [[key value] (str/split semiFormat #"!~")]
(emit {:notExpression {:filter {:fieldName key :stringFilter {:values value :matchType "PARTIAL_REGEXP"}}}}))
"=@" (let [[key value] (str/split semiFormat #"=@")]
(emit {:filter {:fieldName key :stringFilter {:values value :matchType "CONTAINS"}}}))
"!@" (let [[key value] (str/split semiFormat #"!@")]
(emit {:notExpression {:filter {:fieldName key :stringFilter {:values value :matchType "CONTAINS"}}}}))
"==" (let [[key value] (str/split semiFormat #"==")]
(emit {:filter {:fieldName key :stringFilter {:values value :matchType "EXACT"}}}))
"!=" (let [[key value] (str/split semiFormat #"!=")]
(emit {:notExpression {:filter {:fieldName key :stringFilter {:values value :matchType "EXACT"}}}}))
(println "x is not defined"))))))
{:expressions (deref result)}))