ClojureDocs

导航

命名空间

condp

clojure.core

1.0 之后提供 (来源)
  • (condp pred expr & clauses)
Takes a binary predicate, an expression, and a set of clauses.
Each clause can take the form of either:
 test-expr result-expr
 test-expr :>> result-fn
 Note :>> is an ordinary keyword.
 For each clause, (pred test-expr expr) is evaluated. If it returns
logical true, the clause is a match. If a binary clause matches, the
result-expr is returned, if a ternary clause matches, its result-fn,
which must be a unary function, is called with the result of the
predicate as its argument, the result of that call being the return
value of condp. A single default expression can follow the clauses,
and its value will be returned if no clause matches. If no default
expression is provided and no clause matches, an
IllegalArgumentException is thrown.
13 Examples
;; Taken from the excellent clojure tutorial:
;; http://java.ociweb.com/mark/clojure/article.html

(print "Enter a number: ")
(flush) ; stays in a buffer otherwise
(let [line (read-line)
      value (try
              (Integer/parseInt line)
              (catch NumberFormatException e line))] ; use string val if not int
  (println
    (condp = value
      1 "one"
      2 "two"
      3 "three"
      (str "unexpected value, \"" value \")))
  (println
    (condp instance? value
       Number (* value 2)
       String (* (count value) 2))))
;; (some #{4 5 9} [1 2 3 4]) 
;;  is the first matching clause, 
;;  the match value is 4 which is decremented
(condp some [1 2 3 4]
  #{0 6 7} :>> inc
  #{4 5 9} :>> dec
  #{1 2 3} :>> #(+ % 3))
;;=> 3
;; in this case there is no matching clause
;; so an exception is raised.
(condp some [1 2 3 4]
   #{0 6 7} :>> inc
   #{5 9}   :>> dec)

;; java.lang.IllegalArgumentException: No matching clause: [1 2 3 4]
;; a composite predicate which parses a string with "re-seq" 
;; producing a list which is made into a "seq".
(condp (comp seq re-seq) "foo=bar"
  #"[+](\w+)"    :>> #(vector (-> % first (nth 1) keyword) true)
  #"[-](\w+)"    :>> #(vector (-> % first (nth 1) keyword) false)
  #"(\w+)=(\S+)" :>> #(let [x (first %)]
                        [(keyword (nth x 1)) (nth x 2)]))
;;=> [:foo "bar"]
;; See examples for "if" explaining Clojure's idea of logical true
;; and logical false.
;;this is with liberator
;;branching on request method
(defresource my-resource
  :exists? (fn [{:keys [db] {query-params :query-params 
                             body :body 
                             method :request-method} 
                 :request}]
             
             (condp = method
               :get (my-get-exists-fn)
               :post (my-post-exists-fn))))
;; a recursive function to calculate length
;; same as 'count'
(defn length [lst]
    (condp = lst
        (list) 0 ; if empty list result 0
        (+ 1 (length (rest lst))))) ; default expression

(length '(1 2 3))
;;=> 3
;; test arguments against various binary predicates
(condp apply [2 3]
  = "eq"
  < "lt"
  > "gt")
;;=> "lt"

;; test argument against various unary predicates
(condp apply [:foo]
  string? "it's a string"
  keyword? "it's a keyword"
  symbol? "it's a symbol"
  fn? "it's a function"
  "something else!")
;;=> "it's a keyword"
; This function is part of a great solution to the "fizzbuzz" interview question.
; Let's review 
; Players take turns to count incrementally, 
; replacing any number divisible by three with the word "fizz",  
; any number divisible by five with the word "buzz", and 
; any number divisible by both three and five with the word "fizzbuzz".
(defn fizz-buzz [n]
  (condp #(zero? (mod %2 %1)) n
    15 "fizzbuzz"
    3  "fizz"
    5  "buzz"
    n))

(into [] (map fizz-buzz) (range 1 20))
;;=> [1 2 "fizz" 4 "buzz" "fizz" 7 8 "fizz" "buzz" 
;;    11 "fizz" 13 14 "fizzbuzz" 16 17 "fizz" 19]
;; Test a string against multiple regexps, and do something different
;; with the match each time. 
(condp re-matches "17->42"
  #"(\w+)->(\w+)" :>> (fn [[_ p1 p2]]
                        {:start p1 :end p2})

  #"(\w+)->$" :>> (fn [[_ p1]]
                    {:start p1})

  #"\w+" :>> (fn [[p]]
               {:fixed p})

  nil)
; => {:start "17" :end "42"}
;if you are using the function literal already and can't nest

(#(condp (fn [clause expr] (clojure.string/includes? expr clause)) "transaction-result-kafka"
  "transaction-result" 1
  "transaction-failure" 4
  (do
    (str "got message with nil topic")
    nil)))
;=> 1
;; We can use symbols in the test-expression; this isn't possible with 'case'
(defn id-resolver
      [id]
      (let [id-a "a"
            id-b "b"
	    id-c "c"]
       (condp = id
	 id-a {:response-a "id-a"}
	 id-b {:response-b "id-b"}
	 id-c {:response-c "id-c"})))

(id-resolver "a")
;; => {:response-a "id-a"}
;; Want to apply multiple predicates to the same expr? 
;; Not saying you should, but here is how you could.

(def events [{:timestamp "2021-01-01" :source nil :destination 1   :litres 1    :price-per-litres 1}
             {:timestamp "2021-01-02" :source 1   :destination 2   :litres 0.5  :price-per-litres nil}
             {:timestamp "2021-01-02" :source nil :destination 1   :litres 1    :price-per-litres 2}
             {:timestamp "2021-01-02" :source 2   :destination nil :litres 0.25 :price-per-litres nil}])

(map (fn [event]
       (condp (fn [preds e] ((apply every-pred preds) e)) event
           [:price-per-litres :destination]    :insert
           [:source :destination]              :transfer
           [:source (complement :destination)] :withdrawal))
       events)
;; => (:insert :transfer :insert :withdrawal)
See Also

Takes a set of test/expr pairs. It evaluates each test one at a time. If a test returns logical t...

Added by zk

Evaluates test.

Added by jafingerhut

Takes an expression, and a set of clauses. Each clause can take the form of either: test-const...

Added by cloojure
1 Note
    By , created 8.7 years ago

    A lot of these examples show the pattern:

    (condp = value
      :a "a"
      :b "b"
      ...)
    

    Which is the same as:

    (case value
      :a "a"
      :b "b"
      ...)