ClojureDocs

导航

命名空间

apply

clojure.core

从 1.0 开始提供 (来源)
  • (apply f args)
  • (apply f x args)
  • (apply f x y args)
  • (apply f x y z args)
  • (apply f a b c d & args)
Applies fn f to the argument list formed by prepending intervening arguments to args.
18 Examples
(def *strings* ["str1" "str2" "str3"])
;; #'user/*strings*

;; Oops!
(str *strings*)
;;=> "[\"str1\" \"str2\" \"str3\"]"

;; Yay!
(apply str *strings*)
;;=> "str1str2str3"

;; Note the equivalence of the following two forms
(apply str ["str1" "str2" "str3"])  ;;=> "str1str2str3"
(str "str1" "str2" "str3")          ;;=> "str1str2str3"
;; If you were to try
(max [1 2 3])
;;=> [1 2 3]

;; You would get '[1 2 3]' for the result. In this case, 'max' has received one
;; vector argument, and the largest of its arguments is that single vector.

;; If you would like to find the largest item **within** the vector, you would need
;; to use `apply`

(apply max [1 2 3])
;;=> 3

;; which is the same as 
(max 1 2 3)
;;=> 3
;; Here's an example that uses a optional second argument, x:

(apply map vector [[:a :b] [:c :d]])
;;=> ([:a :c] [:b :d])

;; In this example, 'f' = 'map', 'x' = 'vector', and args = '[:a :b] [:c :d]',
;; making the above code equivalent to

(map vector [:a :b] [:c :d])
;;=> ([:a :c] [:b :d]) ;Same answer as above

;; It might help to think of 'map' and 'vector' as "slipping inside" the argument
;; list ( '[[:a :b] [:c :d]]' ) to give '[map vector [:a :b] [:c :d]]' , which 
;; then becomes the executable form '(map vector [:a :b] [:c :d])' .
;; only functions can be used with apply.  'and' is a macro
;; because it needs to evaluate its arguments lazily and so
;; does not work with apply.
(apply and (list true true false true))
;; RuntimeException : cannot take value of a macro

;; This can be circumvented with another macro.
;; But understand what is happening
;; http://stackoverflow.com/questions/5531986/treat-clojure-macro-as-a-function
(defmacro make-fn [m] 
 `(fn [& args#]
    (eval 
      (cons '~m args#))))

(apply (make-fn and) '(true true false true))
;;=> false

;; 'apply' is used to apply an operator to its operands. 
(apply + '(1 2))  ; equivalent to (+ 1 2)
;;=> 3


;; You can also put operands before the list of 
;; operands and they'll be consumed in the list of operands

(apply + 1 2 '(3 4))  ; equivalent to (apply + '(1 2 3 4))
;;=> 10
;; You can use map and apply together to drill one level deep in a collection
;; of collections, in this case returning a collection of the max of each
;; nested collection

(map #(apply max %) [[1 2 3][4 5 6][7 8 9]])
;;=> (3 6 9)
;; Using `apply` with optional keyword parameters:

(defn add2 [a & {:keys [plus] :or {plus 0}}]
  (+ 2 plus a))

(add2 4)                    ; => 6
(add2 4 :plus 1)            ; => 7
(apply add2 [4])            ; => 6
(apply add2 [4 {:plus 1}])  ; => IllegalArgumentException
(apply add2 [4 :plus 1])    ; => 7
;; Transpose a matrix
(def A [[1 2]
        [3 4]])

(apply map vector A) ;  ([1 3] [2 4])
;; Use apply to map a function over a collection of pairs of arguments

(map (partial apply +) [[1 2] [3 4]]) ; => (3 7)

;; this is equivalent to '((+ 1 2) (+ 3 4))
; Remove elements from a set with disj

(disj #{1 2 3} 2 3) 
=> #{1}

; Relative complement of two sets (difference)

(apply disj #{2 3 4} #{1 2 3})
=> #{4}

; the above is same as calling
(disj #{2 3 4} 1 2 3)
;;practical example

(def entries [{:month 1 :val 12}
              {:month 2 :val 3}
              {:month 3 :val 32}
              {:month 4 :val 18}
              {:month 5 :val 32}
              {:month 6 :val 62}
              {:month 7 :val 12}
              {:month 8 :val 142}
              {:month 9 :val 52}
              {:month 10 :val 18}
              {:month 11 :val 23}
              {:month 12 :val 56}])

(apply max (map
            #(:val %)
            entries))
;;return 142
;;this translates into (max 12 3 32 18 32 62 12 142 52 18 23 56)
(apply + [2 3 4])
;;9

(apply + 1 [2 3 4])
;;10

(apply max [1 3 2])
;;3

(apply max 4 [1 3 2])
;;4

(apply str ["a" "b" "c"])
;;"abc"

(apply str "d" ["a" "b" "c"])
;;"dabc"

(str "Hi, here: " (apply str (for [i (range 5)] i)) " Cheers!")
;; "Hi, here: 01234 Cheers!"
(reduce #(apply assoc %1 %2) {} [[:a 1] [:b 2]])

;;{:a 1, :b 2}
(defn chunks
  "Lazily break up map of colls into maps of chunks of n records (default 100 000).
  Truncates at shortest coll (chunk-wise)."
  ([m] (chunks 100000 m))
  ([n m] (apply map merge (repeatedly sorted-map)
           (for [[k v] m]
             (for [part (partition-all n v)]
               {k part})))))

(chunks 2 {:b [1 2 3] :a [1 2 3 4] :c [1 2 3 4 5]})
=> ({:a (1 2), :b (1 2), :c (1 2)}
    {:a (3 4), :b (3), :c (3 4)})

(defn non-truncating-chunks
  ([m] (chunks 100000 m))
  ([n m] (let [partitioned-lists
               ;; '(({k0 part0} {k0 part1} ... nil nil ...)
               ;;   ({k1 part0} {k1 part1} ... nil nil ...)
               ;;   ...)
               (for [[k v] m]
                 ;; '({k part0} {k part1} ... nil nil ... )
                 (concat ; append nils to prevent map truncating at shortest
                   (for [part (partition-all n v)]
                     {k part})
                   (repeat nil)))]
           ;; '(({k0 part0} {k1 part0} ...)
           ;;   ({k0 part1} {k1 part1} ...)
           ;;   ...)
           (for [ls (apply map list partitioned-lists)
                 :while (not-every? nil? ls)]
             (apply merge (sorted-map) ls)))))

(non-truncating-chunks 2 {:b [1 2 3] :a [1 2 3 4] :c [1 2 3 4 5]})
=> ({:a (1 2), :b (1 2), :c (1 2)}
    {:a (3 4), :b (3), :c (3 4)}
    {:c (5)})
;; Based in the example from the great book CLOJURE for the BRAVE and TRUE
;; https://www.braveclojure.com/core-functions-in-depth/

(def countries [:peru :mexico])

(defn add-first
   [target addition]
   (apply conj [addition] target))

(add-first countries :brazil)

;; [:brazil :peru :mexico]
;; If `apply` is called on a function having optional arguments as shown in
;; `function-2`, you must pre-manipulate the arguments before calling `apply`

(defn function-2
  [arg1 & {:keys [a b c]
           :as all-optionals
           :or {a 42}}]
  (list arg1 a b c all-optionals))

;; Suppose you'd like to call `function-2` from `function-1` passing along 
;; the *same* optional arguments.

;; In this example, the call-site of `function-1` may contain any keyword 
;; argument for `function-1` or for `function-2`.

(defn function-1
  [arg1 & {:keys [c d e]
           :as all-optionals
           :or {d 42}}]
  (apply function-2 arg1 (mapcat identity all-optionals)))

(function-1 1)
;; [arg1 1 a 42 b nil c nil all-optionals nil]

(function-1 1 :c 2)
;; [arg1 1 a 42 b nil c 2 all-optionals {:c 2}]

(function-1 1 :c 2 :a 3)
;; [arg1 1 a 3 b nil c 2 all-optionals {:c 2, :a 3}]
(def input-2 ["P1" "R2" "A3" "D4" "E5" "e6" "p7"])

(apply map vector input-2)
;; => ([\P \R \A \D \E \e \p] [\1 \2 \3 \4 \5 \6 \7])

is same as writing using map form :

(map vector (nth input-2 0)
     (nth input-2 1)
     (nth input-2 2)
     (nth input-2 3)
     (nth input-2 4)
     #_(nth input-2 5)
     ,)
;; => ([\P \R \A \D \E] [\1 \2 \3 \4 \5])

(apply map #(println %&) input-2)
;; => (P R A D E e p)
;;    (nil(1 2 3 4 5 6 7)
;;     nil)

further playaround like below to get more comfortable
(map vector "P1" "R2")
;; => ([\P \R] [\1 \2])
;; apply can be used to check if a sequence is already sorted

;; Ascending order
(apply < [1 2 3 4 5])
;; => true

(apply < (range 100))
;; => true

;; Descending order
(apply > [5 4 3 2 1])
;; => true

(apply < (range 100 0 -1))
;; => true
See Also

Returns a lazy sequence consisting of the result of applying f to the set of first items of each c...

Evaluates the form data structure (not text!) and returns the result.

Added by boxie

For use in macros. argv is an argument list, as in defn. expr is a quoted expression using the s...

Added by boxie

f should be a function of 2 arguments. If val is not supplied, returns the result of applying f to...

Added by zk

Takes a function f and fewer than the normal arguments to f, and returns a fn that takes a variabl...

Added by berczeck
2 Notes
    By , created 9.6 years ago, updated 9.6 years ago

    The first example on the page, does not work on the REPL. It gives the following error:

     (def *strings* ["str1" "str2" "str3"])" 

    Warning: strings not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic strings or change the name.

    Should this be prefixed by - "^:dynamic"?

    By , created 6.7 years ago, updated 6.7 years ago

    It looks like apply when used with a lazy sequence forces the realization of the first four elements.

    (take 1
          (apply concat
                 (repeatedly #(do
                                (println "called")
                                (range 1 10)))))
    
    => "called"
    => "called"
    => "called"
    => "called"
    

    See: https://stackoverflow.com/questions/51959298/clojure-apply-that-does-not-realize-the-first-four-elements-of-a-lazy-sequence