如何在clojure中循环内的case语句下将新元素推送到地图中

问题描述 投票:0回答:3

我正在编写 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 ... }

clojure
3个回答
0
投票

让 vs def

过度使用 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))

没有 println

我不确定我是否理解 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))))

看到“重新匹配”行执行多项任务(即找到匹配项并分离出您之前分别完成的键和值)


0
投票

也许你想要这样的东西:

(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 #";"))}})

在这里,匹配类型映射被明确地赋予函数。 (参考透明度)。这些功能更容易测试。


-1
投票

在 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)}))
© www.soinside.com 2019 - 2024. All rights reserved.