Back
group-by (clj)
(source)function
(group-by f coll)
Returns a map of the elements of coll keyed by the result of
f on each element. The value at each key will be a vector of the
corresponding elements, in the order they appeared in coll.
Examples
typedclojure/typedclojure
(ns ^:no-doc typed.ann.clojure
"Type annotations for the base Clojure distribution."
#?(:cljs (:require-macros [typed.ann-macros.clojure :as macros]))
(:require [clojure.core :as cc]
[typed.clojure :as t]
#?(:clj [typed.ann-macros.clojure :as macros])
#?(:clj typed.ann.clojure.jvm) ;; jvm annotations
#?(:clj clojure.core.typed))
#?(:clj
(:import (clojure.lang PersistentHashSet PersistentList
APersistentMap #_IPersistentCollection
#_ITransientSet
IRef)
(java.util Comparator Collection))))
cc/first (t/All [x] (t/IFn [(t/HSequential [x t/Any :*]) :-> x
:object {:id 0 :path [(Nth 0)]}]
[(t/EmptySeqable x) :-> nil]
[(t/NonEmptySeqable x) :-> x]
[(t/Seqable x) :-> (t/Option x)]))
cc/second (t/All [x] (t/IFn [(t/HSequential [t/Any x t/Any :*]) :-> x
:object {:id 0 :path [(Nth 1)]}]
[(t/Option (t/I (t/Seqable x) (t/CountRange 0 1))) :-> nil]
[(t/I (t/Seqable x) (t/CountRange 2)) :-> x]
[(t/Seqable x) :-> (t/Option x)]))
cc/ffirst (t/All [x] [(t/Seqable (t/Seqable x)) :-> (t/Nilable x)])
cc/nfirst (t/All [x] [(t/Seqable (t/Seqable x)) :-> (t/NilableNonEmptyASeq x)])
cc/group-by (t/All [x y] [[x :-> y] (t/Seqable x) :-> (t/Map y (t/NonEmptyAVec x))])
cc/fnext (t/All [x] [(t/Seqable x) :-> (t/Option x)])
cc/nnext (t/All [x] [(t/Seqable x) :-> (t/NilableNonEmptyASeq x)])
cc/nthnext (t/All [x] (t/IFn [nil t/AnyInteger :-> nil]
[(t/Seqable x) t/AnyInteger :-> (t/NilableNonEmptyASeq x)]))
cc/rest (t/All [x] [(t/Seqable x) :-> (t/ASeq x)])
cc/last (t/All [x] (t/IFn [(t/NonEmptySeqable x) :-> x]
[(t/Seqable x) :-> (t/U nil x)]))
cc/butlast (t/All [x] [(t/Seqable x) :-> (t/NilableNonEmptyASeq x)])
cc/next (t/All [x] (t/IFn [(t/Option (t/Coll x)) :-> (t/NilableNonEmptyASeq x)
:filters {:then (& (is (t/CountRange 2) 0)
(! nil 0))
:else (| (is (t/CountRange 0 1) 0)
(is nil 0))}]
[(t/Seqable x) :-> (t/NilableNonEmptyASeq x)]))
ReactiveX/RxClojure
(ns rx.lang.clojure.core-test
(:require [rx.lang.clojure.core :as rx]
[rx.lang.clojure.blocking :as b]
[rx.lang.clojure.future :as f]
[clojure.test :refer [deftest is testing are]]))
(deftest test-group-by
(let [xs [{:k :a :v 1} {:k :b :v 2} {:k :a :v 3} {:k :c :v 4}]]
(testing "with just a key-fn"
(is (= [[:a {:k :a :v 1}]
[:a {:k :a :v 3}]
[:b {:k :b :v 2}]
[:c {:k :c :v 4}]]
(->> xs
(rx/seq->o)
(rx/group-by :k)
(rx/mapcat (fn [[k vo :as me]]
(is (instance? clojure.lang.MapEntry me))
(rx/map #(vector k %) vo)))
(b/into [])))))
; TODO reinstate once this is implemented
; see https://github.com/Netflix/RxJava/commit/02ccc4d727a9297f14219549208757c6e0efce2a
#_(testing "with a val-fn"
(is (= [[:a 1]
[:b 2]
[:a 3]
[:c 4]]
(->> xs
(rx/seq->o)
(rx/group-by :k :v)
(rx/mapcat (fn [[k vo :as me]]
(is (instance? clojure.lang.MapEntry me))
(rx/map #(vector k %) vo)))
(b/into [])))))))
; group-by is a good way to test merge behavior without truly async code
; here the :a and :b observables are interleaved when merged
(let [xs [{:k :a :v 1} {:k :b :v 2} {:k :a :v 3} {:k :c :v 4}]]
(is (= [[:a {:k :a :v 1}]
[:b {:k :b :v 2}]
[:a {:k :a :v 3}]
[:c {:k :c :v 4}]]
(->> xs
(rx/seq->o)
(rx/group-by :k)
(rx/flatmap (fn [[k vo :as me]]
(is (instance? clojure.lang.MapEntry me))
(rx/map #(vector k %) vo)))
(b/into [])))))
; still looking for a simple demo of merging for the multi-arg case
; Here, because ys is "inline", the interleaving is removed. sigh.
(let [xs [{:k :a :v 1} {:k :b :v 2} {:k :a :v 3} {:k :c :v 4}]
ys [:ay :by :cy]]
(is (= [[:a {:k :a :v 1} :ay]
[:a {:k :a :v 3} :ay]
[:b {:k :b :v 2} :by]
[:c {:k :c :v 4} :cy]]
(->> (rx/flatmap (fn [[k vo :as me] y]
(is (instance? clojure.lang.MapEntry me))
(rx/map #(vector k % y) vo))
(->> xs
rx/seq->o
(rx/group-by :k))
(rx/seq->o ys))
(b/into []))))))
fluree/db
(ns json-ld.query
(:require [clojure.core.async :as async]
[fluree.db.flake :as flake]
[fluree.db.json-ld.api :as fluree]
[fluree.db.util.async :refer [<?? go-try channel?]]
[fluree.db.query.range :as query-range]
[fluree.db.constants :as const]
[fluree.db.dbproto :as dbproto]
[fluree.db.did :as did]
[fluree.json-ld :as json-ld]
[fluree.db.indexer.default :as indexer]
[fluree.db.indexer.proto :as idx-proto]
[fluree.db.util.log :as log]
[fluree.db.index :as index]
[criterium.core :as criterium]
[fluree.db.query.analytical-parse :as q-parse]))
@(fluree/query db {:select ['?name '?last '(sum ?favNums)]
:where [['?s :schema/name '?name]
['?s :ex/last '?last]
['?s :ex/favNums '?favNums]]
:group-by ['?name '?last]})
fluree/ledger
(ns fluree.db.ledger.docs.query.advanced-query
(:require [clojure.test :refer :all]
[fluree.db.test-helpers :as test]
[fluree.db.ledger.docs.getting-started.basic-schema :as basic]
[fluree.db.api :as fdb]
[clojure.core.async :as async]
[fluree.db.util.log :as log]))
(deftest group-by-with-limit-offset
(testing "Group By query with limit returns first two full results"
(let [query-all {:select "?favNums"
:where [["?e" "person/favNums" "?favNums"]]
:groupBy "?e"}
query-limit {:select "?favNums"
:where [["?e" "person/favNums" "?favNums"]]
:groupBy "?e"
:limit 2}
query-offset {:select "?favNums"
:where [["?e" "person/favNums" "?favNums"]]
:groupBy "?e"
:offset 2
:limit 2}
db (basic/get-db test/ledger-chat)
res-all (async/<!! (fdb/query-async db query-all))
res-limit (async/<!! (fdb/query-async db query-limit))
res-offset (async/<!! (fdb/query-async db query-offset))]
(deftest group-by-with-having
(testing "Group By query with 'having' statement defined for filter"
(let [q-all {:select "(sum ?favNums)"
:where [["?e" "person/favNums" "?favNums"]]
:groupBy "?e"}
q-having {:select "(sum ?favNums)"
:where [["?e" "person/favNums" "?favNums"]]
:groupBy "?e"
:having (str '(< 200 (sum ?favNums)))}
q-having+and {:select "(sum ?favNums)"
:where [["?e" "person/favNums" "?favNums"]]
:groupBy "?e"
:having (str '(and (< 200 (sum ?favNums)) (> 1900 (sum ?favNums))))}
db (basic/get-db test/ledger-chat)
res-all (async/<!! (fdb/query-async db q-all))
res-having (async/<!! (fdb/query-async db q-having))
res-having+and (async/<!! (fdb/query-async db q-having+and))
;; get a vector of all ?favNums sums
all-sums (vals res-all)]
(deftest advanced-query-test
(crawl-graph)
(crawl-graph-reverse)
(crawl-graph-reverse-add)
(select-no-ns-preds)
(select-with-as)
(select-with-as-and-limit)
(graphql-with-reverse-ref)
(crawl-graph-two)
;(crawl-graph-two-with-recur)
(aggregate-binding)
(group-by-with-limit-offset)
(group-by-with-having)
(multi-query))
;(multi-query-with-error)
ghl3/dataframe
(ns dataframe.frame-test
(:require [dataframe.frame :as frame :refer [index]]
[expectations :refer [expect expect-focused more-of]]
[dataframe.series :as series]
[clojure.core :as core]))
(expect (more-of grouped
(frame/frame {:a [1 2] :b [10 20]} [0 1]) (:foo grouped)
(frame/frame {:a [3] :b [30]} [2]) (:bar grouped))
(frame/group-by
(frame/frame {:a [1 2 3] :b [10 20 30]})
[:foo :foo :bar]))
(expect (more-of grouped
(frame/frame {:a [3 2] :b [30 20]} [2 1]) (:foo grouped)
(frame/frame {:a [1] :b [10]} [0]) (:bar grouped))
(frame/group-by
(frame/frame {:a [1 2 3] :b [10 20 30]})
(series/series [:foo :foo :bar] [2 1 0])))
(expect (more-of grouped
(frame/frame {:a [1 1] :b [10 20]} [0 1]) (get grouped 1)
(frame/frame {:a [3] :b [30]} [2]) (get grouped 3))
(frame/group-by-fn
(frame/frame {:a [1 1 3] :b [10 20 30]}) :a))
(expect (more-of grouped
(frame/frame {:a [1 10] :b [10 1]} [0 2]) (get grouped 11)
(frame/frame {:a [1] :b [5]} [1]) (get grouped 6)
(frame/frame {:a [10] :b [17]} [3]) (get grouped 27))
(frame/with-> (frame/frame {:a [1 1 10 10] :b [10 5 1 17]})
(frame/group-by (series/add $a $b))))