├── doc └── intro.md ├── .gitignore ├── test └── clj_linq │ └── core_test.clj ├── target └── stale │ └── extract-native.dependencies ├── project.clj ├── src └── clj_linq │ ├── linq_generationoperators.clj │ ├── linq_queryexecution.clj │ ├── linq_miscoperators.clj │ ├── linq_quantifiers.clj │ ├── linq_conversions.clj │ ├── linq_elementoperators.clj │ ├── core.clj │ ├── linq_restrictions.clj │ ├── linq_joinoperators.clj │ ├── linq_grouping.clj │ ├── linq_setoperators.clj │ ├── linq_partitioning.clj │ ├── linq_ordering.clj │ ├── data.clj │ ├── linq_projections.clj │ └── linq_aggregateoperators.clj ├── LICENSE └── README.md /doc/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction to scratch 2 | 3 | TODO: write [great documentation](http://jacobian.org/writing/great-documentation/what-to-write/) 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | pom.xml 2 | *jar 3 | /lib/ 4 | /classes/ 5 | /targets/ 6 | .lein-deps-sum 7 | .lein-repl-history 8 | .nrepl-port 9 | *.dependencies 10 | 11 | target/repl-port 12 | -------------------------------------------------------------------------------- /test/clj_linq/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns scratch.core-test 2 | (:require [expectations :refer :all] 3 | [scratch.core :refer :all])) 4 | 5 | ;; linq1: Where - Simple 1 6 | (expect 1 7 | (do 1)) 8 | -------------------------------------------------------------------------------- /target/stale/extract-native.dependencies: -------------------------------------------------------------------------------- 1 | ([:dependencies ([org.clojure/clojure "1.5.1"] [org.clojure/data.json "0.2.3"] [clj-time/clj-time "0.6.0"] [lein-autoexpect/lein-autoexpect "1.0"] [expectations/expectations "1.4.56"] [org.clojure/tools.nrepl "0.2.3" :exclusions ([org.clojure/clojure])] [clojure-complete/clojure-complete "0.2.3" :exclusions ([org.clojure/clojure])])]) -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject clj-linq "0.1.0-SNAPSHOT" 2 | :description "FIXME: write description" 3 | :url "http://example.com/FIXME" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[org.clojure/clojure "1.5.1"] 7 | [org.clojure/data.json "0.2.3"] 8 | [clj-time "0.6.0"] 9 | [lein-autoexpect "1.0"] 10 | [expectations "1.4.56"]] 11 | :main clj-linq.core) 12 | -------------------------------------------------------------------------------- /src/clj_linq/linq_generationoperators.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-generationoperators 2 | (:require [clj-linq.data :refer :all])) 3 | 4 | ;; linq65: Range 5 | (defn linq65 [] 6 | (let [numbers (for [n (range 100 151)] 7 | {:number n, 8 | :odd-even (if (= (mod n 2) 1) "odd" "even")})] 9 | (doseq [n numbers] (println "The number" (:number n) "is" (:odd-even n))))) 10 | 11 | ;; linq66: Repeat 12 | (defn linq66 [] 13 | (let [numbers (repeat 10 7)] 14 | (doseq [n numbers] (println n)))) 15 | 16 | (def examples [linq65 linq66]) 17 | -------------------------------------------------------------------------------- /src/clj_linq/linq_queryexecution.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-queryexecution 2 | (:require [clj-linq.data :refer :all])) 3 | 4 | ;; linq99: Deferred Execution 5 | (defn linq99 [] 6 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 7 | i (atom 0) 8 | q (map (fn [x] (swap! i inc)) (range 10))] 9 | (println @i (count q) @i))) 10 | 11 | ;; linq100: Immediate Execution 12 | (defn linq100 [] 13 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 14 | i (atom 0) 15 | q (into [] (map (fn [x] (swap! i inc)) (range 10)))] 16 | (println @i (count q) @i))) 17 | 18 | ;; linq101: Query Reuse 19 | (defn linq101 [] 20 | (def ^:dynamic numbers [5 4 1 3 9 8 6 7 2 0]) 21 | 22 | (defn low-numbers [] 23 | (filter #(<= % 3) numbers)) 24 | 25 | (println "First run numbers <= 3:") 26 | (doseq [n (low-numbers)] (println n)) 27 | 28 | (println "Second run numbers <= 3") 29 | (binding [numbers (map #(* -1 %) numbers)] 30 | (doseq [n (low-numbers)] (println n)))) 31 | 32 | (def examples [linq99 linq100 linq101]) 33 | 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Demis Bellot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/clj_linq/linq_miscoperators.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-miscoperators 2 | (:require [clj-linq.data :refer :all])) 3 | 4 | ;; linq94: Concat - 1 5 | (defn linq94 [] 6 | (let [numbers-a [0 2 4 5 6 8 9] 7 | numbers-b [1 3 5 7 8] 8 | all-numbers (flatten [numbers-a numbers-b])] 9 | (println "All numbers from both arrays:") 10 | (doseq [n all-numbers] (println n)))) 11 | 12 | ;; linq95: Concat - 2 13 | (defn linq95 [] 14 | (let [products products-list 15 | customers customers-list 16 | customer-names (map :company-name customers) 17 | product-names (map :product-name products) 18 | all-names (flatten [customer-names product-names])] 19 | (println "Customer and product names:") 20 | (doseq [x all-names] (println x)))) 21 | 22 | ;; linq96: EqualAll - 1 23 | (defn linq96 [] 24 | (let [words-a ["cherry" "apple" "blueberry"] 25 | words-b ["cherry" "apple" "blueberry"] 26 | match (= words-a words-b)] 27 | (println "The sequences match:" match))) 28 | 29 | ;; linq97: EqualAll - 2 30 | (defn linq97 [] 31 | (let [words-a ["cherry" "apple" "blueberry"] 32 | words-b ["apple" "blueberry" "cherry"] 33 | match (= words-a words-b)] 34 | (println "The sequences match:" match))) 35 | 36 | (def examples [linq94 linq95 linq96 linq97]) 37 | -------------------------------------------------------------------------------- /src/clj_linq/linq_quantifiers.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-quantifiers 2 | (:require [clj-linq.data :refer :all])) 3 | 4 | ;; linq67: Any - Simple 5 | (defn linq67 [] 6 | (let [words ["believe" "relief" "receipt" "field"] 7 | i-after-e (some #(.contains % "ie") words)] 8 | (println "There is a word that contains in the list that contains 'ei':" i-after-e))) 9 | 10 | ;; linq69: Any - Grouped 11 | (defn linq69 [] 12 | (let [products products-list 13 | product-groups 14 | (->> products 15 | (group-by :category) 16 | (filter #(some (fn [p] (= (:units-in-stock p) 0)) (get % 1))) 17 | (map #(identity {:category (first %), :products (second %)})))] 18 | (doseq [x product-groups] (println x)))) 19 | 20 | ;; linq70: All - Simple 21 | (defn linq70 [] 22 | (let [numbers [1 11 3 19 41 65 19] 23 | only-odd (every? #(= (mod % 2) 1) numbers)] 24 | (println "The list contains only odd numbers:" only-odd))) 25 | 26 | ;; linq72: All - Grouped 27 | (defn linq72 [] 28 | (let [products products-list 29 | product-groups 30 | (->> products 31 | (group-by :category) 32 | (filter #(every? (fn [p] (> (:units-in-stock p) 0)) (second %))) 33 | (map #(identity {:category (first %), :products (second %)})))] 34 | (doseq [x product-groups] (println x)))) 35 | 36 | (def examples [linq67 linq69 linq70 linq72]) 37 | -------------------------------------------------------------------------------- /src/clj_linq/linq_conversions.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-conversions 2 | (:require [clj-linq.data :refer :all])) 3 | 4 | ;; linq54: ToArray 5 | (defn linq54 [] 6 | (let [dbls [1.7 2.3 1.9 4.1 2.9] 7 | sorted-doubles (->> dbls sort reverse)] 8 | (println "Every other double from highest to lowest:") 9 | (doseq [d (take-nth 2 sorted-doubles)] (println d)))) 10 | 11 | ;;linq55: ToList 12 | (defn linq55 [] 13 | (let [words ["cherry", "apple", "blueberry"] 14 | sorted-words (->> words 15 | sort 16 | (apply list))] 17 | (println "The sorted word list:") 18 | (doseq [w sorted-words] (println w)))) 19 | 20 | ;;linq56: ToDictionary 21 | (defn linq56 [] 22 | (let [sorted-records [{:name "Alice", :score 50} 23 | {:name "Bob", :score 40} 24 | {:name "Cathy", :score 45}] 25 | sorted-records-dict (->> sorted-records 26 | (map #(hash-map (:name %) (:score %))) 27 | (into {}))] 28 | (println "Bob's score:" (sorted-records-dict "Bob")))) 29 | 30 | ;; linq57: OfType 31 | (defn linq57 [] 32 | (let [numbers [nil 1.0 "two" 3 "four" 5 "six" 7.0] 33 | dbls (filter #(= (type %) java.lang.Double) numbers)] 34 | (println "Numbers stored as doubles:") 35 | (doseq [d dbls] (println d)))) 36 | 37 | (def examples [linq54 linq55 linq56 linq57]) 38 | -------------------------------------------------------------------------------- /src/clj_linq/linq_elementoperators.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-elementoperators 2 | (:require [clj-linq.data :refer :all])) 3 | 4 | ;; linq58: First - Simple 5 | (defn linq58 [] 6 | (let [products products-list 7 | product-12 (->> products 8 | (filter #(= (:product-id %) 12)) 9 | first)] 10 | (println product-12))) 11 | 12 | ;; linq59: First - Condition 13 | (defn linq59 [] 14 | (let [strings ["zero", "one", "two", "three", "four", 15 | "five", "six", "seven", "eight", "nine"] 16 | starts-with-o (first (filter #(= (first %) \o) strings))] 17 | (println "A string starting with 'o':" starts-with-o))) 18 | 19 | ;; linq61: FirstOrDefault - Simple 20 | (defn linq61 [] 21 | (let [numbers [] 22 | first-num-or-default (get numbers 0 0)] 23 | (println first-num-or-default))) 24 | 25 | ;; linq62: FirstOrDefault - Condition 26 | (defn linq62 [] 27 | (let [products products-list 28 | product-789 (->> products 29 | (filter #(= (:product-id %) 789)) 30 | first)] 31 | (println "Product 789 exists:" (not= product-789 nil)))) 32 | 33 | ;; linq64: ElementAt 34 | (defn linq64 [] 35 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 36 | fourth-low-num (->> numbers 37 | (filter #(> % 5)) 38 | second)] 39 | (println "Second number > 5:" fourth-low-num))) 40 | 41 | (def examples [linq58 linq59 linq61 linq62 linq64]) 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/clj_linq/core.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.core 2 | (:require [clj-linq.data :refer :all] 3 | [clj-linq.linq-restrictions :as restrictions] 4 | [clj-linq.linq-projections :as projections] 5 | [clj-linq.linq-partitioning :as partitioning] 6 | [clj-linq.linq-ordering :as ordering] 7 | [clj-linq.linq-grouping :as grouping] 8 | [clj-linq.linq-setoperators :as setoperators] 9 | [clj-linq.linq-conversions :as conversions] 10 | [clj-linq.linq-elementoperators :as elementoperators] 11 | [clj-linq.linq-generationoperators :as generationoperators] 12 | [clj-linq.linq-quantifiers :as quantifiers] 13 | [clj-linq.linq-aggregateoperators :as aggregateoperators] 14 | [clj-linq.linq-miscoperators :as miscoperators] 15 | [clj-linq.linq-queryexecution :as queryexecution] 16 | [clj-linq.linq-joinoperators :as joinoperators])) 17 | 18 | (defn run-examples [examples] 19 | (doseq [f examples] (prn) (f))) 20 | 21 | (defn -main [& args] 22 | (run-examples restrictions/examples) 23 | (run-examples projections/examples) 24 | (run-examples partitioning/examples) 25 | (run-examples ordering/examples) 26 | (run-examples grouping/examples) 27 | (run-examples setoperators/examples) 28 | (run-examples conversions/examples) 29 | (run-examples elementoperators/examples) 30 | (run-examples generationoperators/examples) 31 | (run-examples quantifiers/examples) 32 | (run-examples aggregateoperators/examples) 33 | (run-examples miscoperators/examples) 34 | (run-examples queryexecution/examples) 35 | (run-examples joinoperators/examples) 36 | ) 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/clj_linq/linq_restrictions.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-restrictions 2 | (:require [clj-linq.data :refer :all])) 3 | 4 | ;; linq1: Where - Simple 1 5 | (defn linq1 [] 6 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 7 | low-numbers (filter #(< % 5) numbers)] 8 | (println "Numbers < 5:") 9 | (doseq [n low-numbers] 10 | (println n)))) 11 | 12 | ;; linq2: Where - Simple 2 13 | (defn linq2 [] 14 | (let [products products-list 15 | sold-out-products (for [p products 16 | :when (= 0 (:units-in-stock p))] 17 | p)] 18 | (println "Sold out products:") 19 | (doseq [p sold-out-products] 20 | (println (:product-name p) " is sold out")))) 21 | 22 | ;; linq3: Where - Simple 3 23 | (defn linq3 [] 24 | (let [products products-list 25 | expensive-in-stock-products 26 | (for [p products-list 27 | :when (and 28 | (> (:units-in-stock p) 0) 29 | (> (:unit-price p) 3))] 30 | p)] 31 | (println "In-stock products that cost more than 3.00:") 32 | (doseq [p expensive-in-stock-products] 33 | (println (:product-name p) "is in stock and costs more than 3.00")))) 34 | 35 | ;; linq4: Where - Drilldown 36 | (defn linq4 [] 37 | (let [customers customers-list 38 | wa-customers (filter #(= (:region %) "WA") customers)] 39 | (println "Customers from Washington and their orders:") 40 | (doseq [c wa-customers] 41 | (println "Customer" (:customer-id c) ": " (:company-name c) ":") 42 | (doseq [o (:orders c)] 43 | (println " Order" (:order-id o) ":" (:order-date o)))))) 44 | 45 | ;; linq5: Where - Indexed 46 | (defn linq5 [] 47 | (let [digits ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"] 48 | short-digits 49 | (for [[i digit] (map-indexed vector digits) 50 | :when (> i (count digit))] 51 | digit)] 52 | (println "Short digits:") 53 | (doseq [d short-digits] 54 | (println "The word" d "is shorter than its value")))) 55 | 56 | (def examples [linq1 linq2 linq3 linq4 linq5]) 57 | -------------------------------------------------------------------------------- /src/clj_linq/linq_joinoperators.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-joinoperators 2 | (:require [clj-linq.data :refer :all])) 3 | 4 | (defn join-group [coll with-coll matcher] 5 | (map (fn [x] {:key x :items (filter (fn [y] (matcher x y)) with-coll)}) 6 | coll)) 7 | 8 | ;; linq102: Cross Join 9 | (defn linq102 [] 10 | (let [categories 11 | ["Beverages", "Condiments", "Vegetables", "Dairy Products", "Seafood"] 12 | products products-list 13 | q (for [pc (join-group categories products #(= %1 (:category %2))) 14 | x (:items pc)] 15 | {:category (:key pc), :product-name (:product-name x)})] 16 | (doseq [v q] 17 | (println (:product-name v) ":" (:category v))))) 18 | 19 | ;; linq103: Group Join 20 | (defn linq103 [] 21 | (let [categories ["Beverages", "Condiments", "Vegetables", "Dairy Products", "Seafood"] 22 | products products-list 23 | q (for [pc (join-group categories products #(= %1 (:category %2)))] 24 | {:category (:key pc), :products (:items pc)})] 25 | (doseq [pc q] 26 | (println (:category pc)) 27 | (doseq [product (:products pc)] 28 | (println " " (:product-name product)))))) 29 | 30 | ;; linq104: Cross Join with Group Join 31 | (defn linq104 [] 32 | (let [categories 33 | ["Beverages", "Condiments", "Vegetables", "Dairy Products", "Seafood"] 34 | products products-list 35 | q (for [pc (join-group categories products #(= %1 (:category %2))) 36 | p (:items pc)] 37 | {:category (:key pc), 38 | :product-name (:product-name p)})] 39 | (doseq [p q] 40 | (println (:product-name p) ":" (:category p))))) 41 | 42 | ;; linq105: Left Outer Join 43 | (defn linq105 [] 44 | (let [categories 45 | ["Beverages", "Condiments", "Vegetables", "Dairy Products", "Seafood"] 46 | products products-list 47 | q (flatten 48 | (for [pc (join-group categories products #(= %1 (:category %2)))] 49 | (if (empty? (:items pc)) 50 | {:category (:key pc), :product-name "(No products)"} 51 | (for [p (:items pc)] 52 | {:category (:key pc), 53 | :product-name (:product-name p)}))))] 54 | (doseq [p q] 55 | (println (:product-name p) ":" (:category p))))) 56 | 57 | 58 | (def examples [linq102 linq103 linq105]) 59 | -------------------------------------------------------------------------------- /src/clj_linq/linq_grouping.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-grouping 2 | (:require [clj-linq.data :refer :all] 3 | [clj-time.core :as time])) 4 | 5 | (defn anagram-comparer [a b] (compare (sort (.toCharArray a)) (sort (.toCharArray b)))) 6 | 7 | ;; linq40: GroupBy - Simple 1 8 | (defn linq40 [] 9 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 10 | number-groups (for [g (group-by #(mod % 5) numbers)] 11 | {:remainder (first g), :numbers (second g)})] 12 | (doseq [g number-groups] 13 | (println "Numbers with a remainder of" (:remainder g) "when divided by 5:") 14 | (doall (map println (:numbers g)))))) 15 | 16 | ;; linq41: GroupBy - Simple 2 17 | (defn linq41 [] 18 | (let [words ["blueberry" "chimpanzee" "abacus" "banana" "apple" "cheese"] 19 | word-groups (for [g (group-by #(first %) words)] 20 | {:first-letter (first g), :words (second g)})] 21 | (doseq [g word-groups] 22 | (println "Words that start with the letter: " (:first-letter g)) 23 | (doall (map println (:words g)))))) 24 | 25 | ;; linq42: GroupBy - Simple 3 26 | (defn linq42 [] 27 | (let [products products-list 28 | order-groups (for [g (group-by #(:category %) products)] 29 | {:category (first g), :products (second g)})] 30 | (doseq [x order-groups] (println x)))) 31 | 32 | ;; linq43: GroupBy - Nested 33 | (defn linq43 [] 34 | (let [customers customers-list 35 | customer-order-groups 36 | (for [c customers] 37 | {:company-name (:company-name c), 38 | :year-groups 39 | (for [yg (group-by #(time/year (:order-date %)) (:orders c))] 40 | {:year (first yg) 41 | :month-groups 42 | (for [mg (group-by #(:order-date %) (second yg))] 43 | {:month (time/month (first mg)), :orders (second mg)})})})] 44 | (doseq [x customer-order-groups] (println x)))) 45 | 46 | ;; linq44: GroupBy - Comparer 47 | (defn linq44 [] 48 | (let [anagrams ["from " " salt" " earn " " last " " near " " form "] 49 | order-groups (group-by #(sort (.toCharArray (.trim %))) anagrams)] 50 | (doseq [x order-groups] (println (second x))))) 51 | 52 | ;; linq45: GroupBy - Comparer, Mapped 53 | (defn linq45 [] 54 | (let [anagrams ["from " " salt" " earn " " last " " near " " form "] 55 | order-groups (group-by #(sort (.toCharArray (.trim %))) 56 | (map #(.toUpperCase %) anagrams))] 57 | (doseq [x order-groups] (println (second x))))) 58 | 59 | (def examples [linq40 linq41 linq42 linq43 linq44 linq45]) 60 | -------------------------------------------------------------------------------- /src/clj_linq/linq_setoperators.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-setoperators 2 | (:require [clj-linq.data :refer :all])) 3 | 4 | (use 'clojure.set) 5 | 6 | ;; linq46: Distinct - 1 7 | (defn linq46 [] 8 | (let [factors-of-300 [2, 2, 3, 5, 5] 9 | unique-factors (distinct factors-of-300)] 10 | (println "Prime factors of 300:") 11 | (doseq [n unique-factors] (println n)))) 12 | 13 | ;; linq47: Distinct - 2 14 | (defn linq47 [] 15 | (let [products products-list 16 | category-names (->> products 17 | (map :category) 18 | distinct)] 19 | (println "Category names:") 20 | (doseq [c category-names] (println c)))) 21 | 22 | ;; linq48: Union - 1 23 | (defn linq48 [] 24 | (let [numbers-a [0 2 4 5 6 8 9] 25 | numbers-b [1 3 5 7 8] 26 | unique-numbers (union (set numbers-a) (set numbers-b))] 27 | (println "Unique numbers from both arrays:") 28 | (doseq [n unique-numbers] (println n)))) 29 | 30 | ;; linq49: Union - 2 31 | (defn linq49 [] 32 | (let [products products-list 33 | customers customers-list 34 | product-first-chars (map #(first (:product-name %)) products) 35 | customer-first-chars (map #(first (:company-name %)) customers) 36 | unique-first-chars (union (set product-first-chars) (set customer-first-chars))] 37 | (println "Unique first letters from Product names and Customer names:") 38 | (doseq [x unique-first-chars] (println x)))) 39 | 40 | ;; linq50: Intersect - 1 41 | (defn linq50 [] 42 | (let [numbers-a [0 2 4 5 6 8 9] 43 | numbers-b [1 3 5 7 8] 44 | common-numbers (intersection (set numbers-a) (set numbers-b))] 45 | (println "Common numbers shared by both arrays:") 46 | (doseq [n common-numbers] (println n)))) 47 | 48 | ;; linq51: Intersect - 2 49 | (defn linq51 [] 50 | (let [products products-list 51 | customers customers-list 52 | product-first-chars (map #(first (:product-name %)) products) 53 | customer-first-chars (map #(first (:company-name %)) customers) 54 | common-first-chars (intersection (set product-first-chars) (set customer-first-chars))] 55 | (println "Common first letters from Product names and Customer names:") 56 | (doseq [x common-first-chars] (println x)))) 57 | 58 | ;; linq52: Except - 1 59 | (defn linq52 [] 60 | (let [numbers-a [0 2 4 5 6 8 9] 61 | numbers-b [1 3 5 7 8] 62 | a-only-numbers (difference (set numbers-a) (set numbers-b))] 63 | (println "Numbers in first array but not second array:") 64 | (doseq [n a-only-numbers] (println n)))) 65 | 66 | ;; linq53: Except - 2 67 | (defn linq53 [] 68 | (let [products products-list 69 | customers customers-list 70 | product-first-chars (map #(first (:product-name %)) products) 71 | customer-first-chars (map #(first (:company-name %)) customers) 72 | product-only-first-chars (difference (set product-first-chars) 73 | (set customer-first-chars))] 74 | (println "First letters from Product names, but not from Customer names:") 75 | (doseq [x product-only-first-chars] (println x)))) 76 | 77 | (def examples [linq46 linq47 linq48 linq49 linq50 linq51 linq52 linq53]) 78 | -------------------------------------------------------------------------------- /src/clj_linq/linq_partitioning.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-partitioning 2 | (:require [clj-linq.data :refer :all])) 3 | 4 | ;; linq20: Select - Simple 1 5 | (defn linq20 [] 6 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 7 | first-3-numbers (take 3 numbers)] 8 | (println "First 3 numbers:") 9 | (doseq [n first-3-numbers] (println n)))) 10 | 11 | ;; linq21: Take - Nested 12 | (defn linq21 [] 13 | (let [customers customers-list 14 | first-3-wa-orders 15 | (take 3 16 | (for [c customers 17 | :when (= (:region c) "WA") 18 | o (:orders c)] 19 | {:customer-id (:customer-id c), 20 | :order-id (:order-id o), 21 | :order-date (:order-date o)}))] 22 | (println "First 3 orders in WA:") 23 | (doseq [x first-3-wa-orders] (println x)))) 24 | 25 | ;; linq22: Skip - Simple 26 | (defn linq22 [] 27 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 28 | all-but-first-4-numbers (drop 4 numbers)] 29 | (println "All but first 4 numbers:") 30 | (doseq [n all-but-first-4-numbers] (println n)))) 31 | 32 | ;; linq23: Skip - Nested 33 | (defn linq23 [] 34 | (let [customers customers-list 35 | all-but-first-2-orders 36 | (drop 2 37 | (for [c customers 38 | :when (= (:region c) "WA") 39 | o (:orders c)] 40 | {:customer-id (:customer-id c), 41 | :order-id (:order-id o), 42 | :order-date (:order-date o)}))] 43 | (println "All but first 2 orders in WA:") 44 | (doseq [o all-but-first-2-orders] (println o)))) 45 | 46 | ;; linq24: TakeWhile - Simple 47 | (defn linq24 [] 48 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 49 | first-numbers-less-than-6 (take-while #(< % 6) numbers)] 50 | (println "First numbers less than 6:") 51 | (doseq [n first-numbers-less-than-6] (println n)))) 52 | 53 | ;; linq25: TakeWhile - Indexed 54 | (defn linq25 [] 55 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 56 | first-small-numbers 57 | (map (fn [[i num]] num) 58 | (take-while (fn [[i num]] (>= num i)) (map-indexed vector numbers)))] 59 | (println "First numbers not less than their position:") 60 | (doseq [n first-small-numbers] (println n)))) 61 | 62 | (defn linq25 [] 63 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 64 | first-small-numbers 65 | (for [[i num] (map-indexed vector numbers) 66 | :while (>= num i)] 67 | num)] 68 | (println "First numbers not less than their position:") 69 | (doseq [n first-small-numbers] (println n)))) 70 | 71 | ;; linq26: SkipWhile - Simple 72 | (defn linq26 [] 73 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 74 | all-but-first-3-numbers (drop-while #(not= (mod % 3) 0) numbers)] 75 | (println "All elements starting from first element divisible by 3:") 76 | (doseq [n all-but-first-3-numbers] (println n)))) 77 | 78 | ;; linq27: SkipWhile - Indexed 79 | (defn linq27 [] 80 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 81 | later-numbers 82 | (map (fn [[i num]] num) 83 | (drop-while (fn [[i num]] (>= num i)) (map-indexed vector numbers)))] 84 | (println "All elements starting from first element less than its position:") 85 | (doseq [n later-numbers] (println n)))) 86 | 87 | 88 | (def examples [linq20 linq21 linq22 linq23 linq24 linq25 linq26 linq27]) 89 | -------------------------------------------------------------------------------- /src/clj_linq/linq_ordering.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-ordering 2 | (:require [clj-linq.data :refer :all])) 3 | 4 | (defn case-insensitive-compare [s1 s2] 5 | (compare (.toLowerCase s1) (.toLowerCase s2))) 6 | 7 | (defn order-by-comparers [comparers xs] 8 | (sort-by 9 | pass-thru 10 | (fn [a1 a2] 11 | (nth (for [x (map #(% a1 a2) comparers) 12 | :when (not= x 0)] x) 13 | 0 0)) 14 | xs)) 15 | 16 | (defn order-by [fns xs] 17 | (sort-by (apply juxt fns) xs)) 18 | 19 | 20 | ;; linq28: SkipWhile - Simple 21 | (defn linq28 [] 22 | (let [words ["cherry" "apple" "blueberry"] 23 | sorted-words (sort words)] 24 | (println "The sorted list of words:") 25 | (doseq [w sorted-words] (println w)))) 26 | 27 | ;; linq29: OrderBy - Simple 2 28 | (defn linq29 [] 29 | (let [words ["cherry" "apple" "blueberry"] 30 | sorted-words (sort-by count words)] 31 | (println "The sorted list of words (by length):") 32 | (doseq [w sorted-words] (println w)))) 33 | 34 | ;; linq30: OrderBy - Simple 3 35 | (defn linq30 [] 36 | (let [products products-list 37 | sorted-products (sort-by :product-name products)] 38 | (doseq [p sorted-products] (println p)))) 39 | 40 | ;; linq31: OrderBy - Comparer 41 | (defn linq31 [] 42 | (let [words ["aPPLE" "AbAcUs" "bRaNcH" "BlUeBeRrY" "ClOvEr" "cHeRry"] 43 | sorted-words (sort-by identity case-insensitive-compare words)] 44 | (doseq [w sorted-words] (println w)))) 45 | 46 | ;; linq32: OrderByDescending - Simple 1 47 | (defn linq32 [] 48 | (let [dbls [1.7 2.3 1.9 4.1 2.9] 49 | sorted-doubles (reverse (sort dbls))] 50 | (println "The doubles from highest to lowest:") 51 | (doseq [d sorted-doubles] (println d)))) 52 | 53 | ;; linq33: OrderByDescending - Simple 2 54 | (defn linq33 [] 55 | (let [products products-list 56 | sorted-products (reverse (sort-by :units-in-stock products))] 57 | (doseq [p sorted-products] (println p)))) 58 | 59 | ;; linq34: OrderByDescending - Comparer 60 | (defn linq34 [] 61 | (let [words ["aPPLE" "AbAcUs" "bRaNcH" "BlUeBeRrY" "ClOvEr" "cHeRry"] 62 | sorted-words (->> words 63 | (sort-by identity case-insensitive-compare) 64 | reverse)] 65 | (doseq [w sorted-words] (println w)))) 66 | 67 | ;; linq35: ThenBy - Simple 68 | (defn linq35 [] 69 | (let [digits ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"] 70 | sorted-digits (order-by [count identity] digits)] 71 | (println "Sorted digits:") 72 | (doseq [d sorted-digits] (println d)))) 73 | 74 | ;; linq36: ThenBy - Comparer 75 | (defn linq36 [] 76 | (let [words ["aPPLE" "AbAcUs" "bRaNcH" "BlUeBeRrY" "ClOvEr" "cHeRry"] 77 | sorted-words (order-by [count (fn [x] (.toLowerCase x))] words)] 78 | (doseq [w sorted-words] (println w)))) 79 | 80 | ;; linq37: ThenByDescending - Simple 81 | (defn linq37 [] 82 | (let [products products-list 83 | sorted-products (order-by [:category #(* -1 (:unit-price %))] products)] 84 | (doseq [p sorted-products] (println p)))) 85 | 86 | ;; linq38: ThenByDescending - Comparer 87 | (defn linq38 [] 88 | (let [words ["aPPLE" "AbAcUs" "bRaNcH" "BlUeBeRrY" "ClOvEr" "cHeRry"] 89 | sorted-words (order-by-comparers 90 | [#(compare (count %1) (count %2)) 91 | #(case-insensitive-compare %2 %1)] 92 | words)] 93 | (doseq [w sorted-words] (println w)))) 94 | 95 | ;; linq39: Reverse 96 | (defn linq39 [] 97 | (let [digits ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"] 98 | sorted-digits (->> digits 99 | (filter #(= (get % 1) \i)) 100 | reverse)] 101 | (println "A backwards list of the digits with a second character of 'i':") 102 | (doseq [d sorted-digits] (println d)))) 103 | 104 | (def examples [linq28 linq29 linq30 linq31 linq32 linq33 linq34 linq35 linq36 linq37 linq38 linq39]) 105 | -------------------------------------------------------------------------------- /src/clj_linq/data.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.data 2 | (:require [clojure.data.json :as json] 3 | [clj-time.local :as ltime])) 4 | 5 | 6 | (defn pass-thru 7 | ([] []) 8 | ([a1] a1) 9 | ([a1 a2] [a1 a2]) 10 | ([a1 a2 & args] (concat [a1 a2] args))) 11 | 12 | (defn log [a] 13 | (println a) 14 | a) 15 | 16 | 17 | (defrecord Product [product-id product-name category unit-price units-in-stock]) 18 | 19 | (def products-list [ 20 | (Product. 1 "Chai" "Beverages" 18.000 39) 21 | (Product. 2 "Chang" "Beverages" 19.000 17) 22 | (Product. 3 "Aniseed Syrup" "Condiments" 10.000 13) 23 | (Product. 4 "Chef Anton's Cajun Seasoning" "Condiments" 22.000 53) 24 | (Product. 5 "Chef Anton's Gumbo Mix" "Condiments" 21.350 0) 25 | (Product. 6 "Grandma's Boysenberry Spread" "Condiments" 25.000 120) 26 | (Product. 7 "Uncle Bob's Organic Dried Pears" "Produce" 30.000 15) 27 | (Product. 8 "Northwoods Cranberry Sauce" "Condiments" 40.000 6) 28 | (Product. 9 "Mishi Kobe Niku" "Meat/Poultry" 97.000 29) 29 | (Product. 10 "Ikura" "Seafood" 31.000 31) 30 | (Product. 11 "Queso Cabrales" "Dairy Products" 21.000 22) 31 | (Product. 12 "Queso Manchego La Pastora" "Dairy Products" 38.000 86) 32 | (Product. 13 "Konbu" "Seafood" 6.000 24) 33 | (Product. 14 "Tofu" "Produce" 23.250 35) 34 | (Product. 15 "Genen Shouyu" "Condiments" 15.500 39) 35 | (Product. 16 "Pavlova" "Confections" 17.450 29) 36 | (Product. 17 "Alice Mutton" "Meat/Poultry" 39.000 0) 37 | (Product. 18 "Carnarvon Tigers" "Seafood" 62.500 42) 38 | (Product. 19 "Teatime Chocolate Biscuits" "Confections" 9.200 25) 39 | (Product. 20 "Sir Rodney's Marmalade" "Confections" 81.000 40) 40 | (Product. 21 "Sir Rodney's Scones" "Confections" 10.000 3) 41 | (Product. 22 "Gustaf's Knäckebröd" "Grains/Cereals" 21.000 104) 42 | (Product. 23 "Tunnbröd" "Grains/Cereals" 9.000 61) 43 | (Product. 24 "Guaraná Fantástica" "Beverages" 4.500 20) 44 | (Product. 25 "NuNuCa Nuß-Nougat-Creme" "Confections" 14.000 76) 45 | (Product. 26 "Gumbär Gummibärchen" "Confections" 31.230 15) 46 | (Product. 27 "Schoggi Schokolade" "Confections" 43.900 49) 47 | (Product. 28 "Rössle Sauerkraut" "Produce" 45.600 26) 48 | (Product. 29 "Thüringer Rostbratwurst" "Meat/Poultry" 123.790 0) 49 | (Product. 30 "Nord-Ost Matjeshering" "Seafood" 25.890 10) 50 | (Product. 31 "Gorgonzola Telino" "Dairy Products" 12.500 0) 51 | (Product. 32 "Mascarpone Fabioli" "Dairy Products" 32.000 9) 52 | (Product. 33 "Geitost" "Dairy Products" 2.500 112) 53 | (Product. 34 "Sasquatch Ale" "Beverages" 14.000 111) 54 | (Product. 35 "Steeleye Stout" "Beverages" 18.000 20) 55 | (Product. 36 "Inlagd Sill" "Seafood" 19.000 112) 56 | (Product. 37 "Gravad lax" "Seafood" 26.000 11) 57 | (Product. 38 "Côte de Blaye" "Beverages" 263.500 17) 58 | (Product. 39 "Chartreuse verte" "Beverages" 18.000 69) 59 | (Product. 40 "Boston Crab Meat" "Seafood" 18.400 123) 60 | (Product. 41 "Jack's New England Clam Chowder" "Seafood" 9.650 85) 61 | (Product. 42 "Singaporean Hokkien Fried Mee" "Grains/Cereals" 14.000 26) 62 | (Product. 43 "Ipoh Coffee" "Beverages" 46.000 17) 63 | (Product. 44 "Gula Malacca" "Condiments" 19.450 27) 64 | (Product. 45 "Rogede sild" "Seafood" 9.500 5) 65 | (Product. 46 "Spegesild" "Seafood" 12.000 95) 66 | (Product. 47 "Zaanse koeken" "Confections" 9.500 36) 67 | (Product. 48 "Chocolade" "Confections" 12.750 15) 68 | (Product. 49 "Maxilaku" "Confections" 20.000 10) 69 | (Product. 50 "Valkoinen suklaa" "Confections" 16.250 65) 70 | (Product. 51 "Manjimup Dried Apples" "Produce" 53.000 20) 71 | (Product. 52 "Filo Mix" "Grains/Cereals" 7.000 38) 72 | (Product. 53 "Perth Pasties" "Meat/Poultry" 32.800 0) 73 | (Product. 54 "Tourtière" "Meat/Poultry" 7.450 21) 74 | (Product. 55 "Pâté chinois" "Meat/Poultry" 24.000 115) 75 | (Product. 56 "Gnocchi di nonna Alice" "Grains/Cereals" 38.000 21) 76 | (Product. 57 "Ravioli Angelo" "Grains/Cereals" 19.500 36) 77 | (Product. 58 "Escargots de Bourgogne" "Seafood" 13.250 62) 78 | (Product. 59 "Raclette Courdavault" "Dairy Products" 55.000 79) 79 | (Product. 60 "Camembert Pierrot" "Dairy Products" 34.000 19) 80 | (Product. 61 "Sirop d'érable" "Condiments" 28.500 113) 81 | (Product. 62 "Tarte au sucre" "Confections" 49.300 17) 82 | (Product. 63 "Vegie-spread" "Condiments" 43.900 24) 83 | (Product. 64 "Wimmers gute Semmelknödel" "Grains/Cereals" 33.250 22) 84 | (Product. 65 "Louisiana Fiery Hot Pepper Sauce" "Condiments" 21.050 76) 85 | (Product. 66 "Louisiana Hot Spiced Okra" "Condiments" 17.000 4) 86 | (Product. 67 "Laughing Lumberjack Lager" "Beverages" 14.000 52) 87 | (Product. 68 "Scottish Longbreads" "Confections" 12.500 6) 88 | (Product. 69 "Gudbrandsdalsost" "Dairy Products" 36.000 26) 89 | (Product. 70 "Outback Lager" "Beverages" 15.000 15) 90 | (Product. 71 "Flotemysost" "Dairy Products" 21.500 26) 91 | (Product. 72 "Mozzarella di Giovanni" "Dairy Products" 34.800 14) 92 | (Product. 73 "Röd Kaviar" "Seafood" 15.000 101) 93 | (Product. 74 "Longlife Tofu" "Produce" 10.000 4) 94 | (Product. 75 "Rhönbräu Klosterbier" "Beverages" 7.750 125) 95 | (Product. 76 "Lakkalikööri" "Beverages" 18.000 57) 96 | (Product. 77 "Original Frankfurter grüne Soße" "Condiments" 13.000 32) 97 | ]) 98 | 99 | (defrecord Customer [customer-id company-name address city region postal-code country phone fax orders]) 100 | (defrecord Order [order-id order-date total]) 101 | 102 | (def all-customers (json/read-str (slurp "resources/Customers.json"))) 103 | 104 | (def customers-list 105 | (map 106 | (fn [x] (Customer. 107 | (x "id") 108 | (x "name") 109 | (x "address") 110 | (x "city") 111 | (x "region") 112 | (x "postalcode") 113 | (x "country") 114 | (x "phone") 115 | (x "fax") 116 | (map #(Order. (% "id") (ltime/to-local-date-time (% "orderdate")) (BigDecimal. (% "total"))) (get (x "orders") "order")) 117 | )) 118 | (get all-customers "customers") 119 | ) 120 | ) 121 | -------------------------------------------------------------------------------- /src/clj_linq/linq_projections.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-projections 2 | (:require [clj-linq.data :refer :all] 3 | [clojure.string :as str] 4 | [clj-time.core :as time] 5 | [clj-time.local :as ltime])) 6 | 7 | 8 | ;; linq6: Select - Simple 1 9 | (defn linq6 [] 10 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 11 | nums-plus-one (map inc numbers)] 12 | (println "Numbers + 1:") 13 | (doseq [n nums-plus-one] (println n)))) 14 | 15 | ;; linq7: Select - Simple 2 16 | (defn linq7 [] 17 | (let [products products-list 18 | product-names (map #(:product-name %) products)] 19 | (println "Product Names:") 20 | (doseq [x product-names] (println x)))) 21 | 22 | ;; linq8: Select - Transformation 23 | (defn linq8 [] 24 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 25 | strings ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"] 26 | text-nums (map strings numbers)] 27 | (println "Number strings:") 28 | (doseq [n text-nums] (println n)))) 29 | 30 | ;; linq9: Select - Anonymous Types 1 31 | (defn linq9 [] 32 | (let [words ["aPPLE", "BlUeBeRrY", "cHeRry"] 33 | upper-lower-words 34 | (for [w words] { :lower (str/lower-case w), :upper (str/upper-case w)})] 35 | (doseq [ul upper-lower-words] 36 | (println "Uppercase:" (:upper ul) ", Lowercase:" (:lower ul))))) 37 | 38 | ;; linq10: Select - Anonymous Types 2 39 | (defn linq10 [] 40 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 41 | strings ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"] 42 | digit-odd-evens 43 | (for [n numbers] {:digit (strings n), :even (= (mod n 2) 0)})] 44 | (doseq [d digit-odd-evens] 45 | (println "The digit" (:digit d) "is" (if (:even d) "even" "odd"))))) 46 | 47 | ;; linq11: Select - Anonymous Types 3 48 | (defn linq11 [] 49 | (let [products products-list 50 | product-infos 51 | (for [p products] 52 | {:product-name (:product-name p), 53 | :category (:category p), 54 | :price (:unit-price p)})] 55 | (println "Product Info:") 56 | (doseq [p product-infos] 57 | (println (:product-name p) "is in the category" (:category p) 58 | "and costs" (:price p))))) 59 | 60 | ;; linq12: Select - Indexed 61 | (defn linq12 [] 62 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 63 | nums-in-place 64 | (map-indexed (fn [i num] {:num num, :in-place (= num i)}) numbers)] 65 | (println "Number: In-place?") 66 | (doseq [n nums-in-place] 67 | (println (:num n) ":" (:in-place n))))) 68 | 69 | ;; linq13: Select - Filtered 70 | (defn linq13 [] 71 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 72 | digits ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"] 73 | low-nums (for [n numbers 74 | :when (< n 5)] 75 | (digits n))] 76 | (println "Numbers < 5:") 77 | (doseq [n low-nums] (println n)))) 78 | 79 | ;; linq14: SelectMany - Compound from 1 80 | (defn linq14 [] 81 | (let [numbers-a [0 2 4 5 6 8 9] 82 | numbers-b [1 3 5 7 8] 83 | pairs (for [a numbers-a 84 | b numbers-b 85 | :when (< a b)] 86 | {:a a, :b b})] 87 | (println "Pairs where a < b:") 88 | (doseq [pair pairs] 89 | (println (:a pair) "is less than" (:b pair))))) 90 | 91 | ;; linq15: SelectMany - Compound from 2 92 | (defn linq15 [] 93 | (let [customers customers-list 94 | orders 95 | (for [c customers 96 | o (:orders c) 97 | :when (< (:total o) 500)] 98 | {:customer-id (:customer-id c), 99 | :order-id (:order-id o), 100 | :total (:total o)})] 101 | (doseq [o orders] (println o)))) 102 | 103 | ;; linq16: SelectMany - Compound from 3 104 | (defn linq16 [] 105 | (let [customers customers-list 106 | orders 107 | (for [c customers 108 | o (:orders c) 109 | :when (time/after? (:order-date o) (time/date-time 1998 1 1))] 110 | {:customer-id (:customer-id c), 111 | :order-id (:order-id o), 112 | :order-date (:order-date o)})] 113 | (doseq [o orders] (println o)))) 114 | 115 | ;;linq17: SelectMany - from Assignment 116 | (defn linq17 [] 117 | (let [customers customers-list 118 | orders 119 | (for [c customers 120 | o (:orders c) 121 | :when (>= (:total o) 2000)] 122 | {:customer-id (:customer-id c), :order-id (:order-id o), :total (:total o)})] 123 | (doseq [o orders] (println o)))) 124 | 125 | ;;linq18: SelectMany - Multiple from 126 | (defn linq18 [] 127 | (let [customers customers-list 128 | cutoff-date (time/date-time 1997 1 1) 129 | orders 130 | (for [c customers 131 | :when (= (:region c) "WA") 132 | o (:orders c) 133 | :when (time/after? (:order-date o) cutoff-date)] 134 | {:customer-id (:customer-id c), :order-id (:order-id o)})] 135 | (doseq [o orders] (println o)))) 136 | 137 | ;;linq19: SelectMany - Indexed 138 | (defn linq19 [] 139 | (let [customers customers-list 140 | customer-orders 141 | (flatten 142 | (map-indexed 143 | (fn [i c] 144 | (map #(str "Customer #" (inc i) " has an order with OrderID " (:order-id %)) 145 | (:orders c))) 146 | customers))] 147 | (doseq [x customer-orders] (println x)))) 148 | 149 | (defn linq19 [] 150 | (let [customers customers-list 151 | customer-orders 152 | (for [[i c] (map-indexed vector customers) 153 | o (:orders c)] 154 | (str "Customer #" (inc i) " has an order with OrderID " (:order-id o)))] 155 | (doseq [x customer-orders] (println x)))) 156 | 157 | 158 | (def examples [linq6 linq7 linq8 linq9 linq10 linq11 linq12 linq13 linq14 linq15 linq16 159 | linq17 linq18 linq19]) 160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /src/clj_linq/linq_aggregateoperators.clj: -------------------------------------------------------------------------------- 1 | (ns clj-linq.linq-aggregateoperators 2 | (:require [clj-linq.data :refer :all])) 3 | 4 | (defn average [coll] (/ (reduce + coll) (count coll))) 5 | 6 | ;; linq73: Count - Simple 7 | (defn linq73 [] 8 | (let [factors-of-300 [2 2 3 5 5] 9 | unique-factors (count (distinct factors-of-300))] 10 | (println "There are" unique-factors "unique factors of 300."))) 11 | 12 | ;; linq74: Count - Conditional 13 | (defn linq74 [] 14 | (let [numbers [4 5 1 3 9 0 6 7 2 0] 15 | odd-numbers (count (for [n numbers :when (= 1 (mod n 2))] n))] 16 | (println "There are" odd-numbers "odd numbers in the list."))) 17 | 18 | ;; linq76: Count - Nested 19 | (defn linq76 [] 20 | (let [customers customers-list 21 | order-counts 22 | (for [c customers] 23 | {:customer-id (:customer-id c) :order-count (count (:orders c))})] 24 | (doseq [x order-counts] (println x)))) 25 | 26 | ;; linq77: Count - Grouped 27 | (defn linq77 [] 28 | (let [products products-list 29 | category-counts 30 | (->> products 31 | (group-by :category) 32 | (map #(identity {:category (first %), 33 | :product-count (count (second %))})))] 34 | (doseq [x category-counts] (println x)))) 35 | 36 | ;; linq78: Sum - Simple 37 | (defn linq78 [] 38 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 39 | num-sum (reduce + numbers)] 40 | (println "The sum of the numbers is " num-sum))) 41 | 42 | ;; linq79: Sum - Projection 43 | (defn linq79 [] 44 | (let [words ["cherry", "apple", "blueberry"] 45 | total-chars (reduce + (map count words))] 46 | (println "There are a total of" total-chars "characters in these words."))) 47 | 48 | ;; linq80: Sum - Grouped 49 | (defn linq80 [] 50 | (let [products products-list 51 | categories 52 | (->> products 53 | (group-by :category) 54 | (map #(identity 55 | {:category (get % 0), 56 | :total-units-in-stock (reduce + (map :units-in-stock (get % 1)))})))] 57 | (doseq [x categories] (println x)))) 58 | 59 | ;; linq81: Min - Simple 60 | (defn linq81 [] 61 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 62 | min-num (apply min numbers)] 63 | (println "The minimum number is" min-num))) 64 | 65 | ;; linq82: Min - Projection 66 | (defn linq82 [] 67 | (let [words ["cherry", "apple", "blueberry"] 68 | shortest-word (apply min (map count words))] 69 | (println "The shortest word is" shortest-word "characters long."))) 70 | 71 | ;; linq83: Min - Grouped 72 | (defn linq83 [] 73 | (let [products products-list 74 | categories 75 | (->> products 76 | (group-by :category) 77 | (map #(identity {:category (first %), 78 | :cheapest-price (apply min (map :unit-price (second %)))})))] 79 | (doseq [c categories] (println c)))) 80 | 81 | ;; linq84: Min - Elements 82 | (defn linq84 [] 83 | (let [products products-list 84 | categories 85 | (for [g (group-by :category products) 86 | :let [min-price (apply min (map :unit-price (second g)))]] 87 | {:category (first g) 88 | :cheapest-products (for [p (second g) 89 | :when (= (:unit-price p) min-price)] p)})] 90 | (doseq [c categories] (println c)))) 91 | 92 | ;; linq85: Max - Simple 93 | (defn linq85 [] 94 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 95 | max-num (apply max numbers)] 96 | (println "The maximum number is" max-num))) 97 | 98 | ;; linq86: Max - Projection 99 | (defn linq86 [] 100 | (let [words ["cherry", "apple", "blueberry"] 101 | longest-word (apply max (map count words))] 102 | (println "The longest word is" longest-word "characters long."))) 103 | 104 | ;; linq87: Max - Grouped 105 | (defn linq87 [] 106 | (let [products products-list 107 | categories 108 | (->> products 109 | (group-by :category) 110 | (map #(identity 111 | {:category (get % 0), 112 | :most-expensive-price (apply max (map :unit-price (get % 1)))})))] 113 | (doseq [c categories] (println c)))) 114 | 115 | ;; linq88: Max - Elements 116 | (defn linq88 [] 117 | (let [products products-list 118 | categories 119 | (for [g (group-by :category products) 120 | :let [max-price (apply max (map :unit-price (second g)))]] 121 | {:category (first g) 122 | :most-expensive-products 123 | (for [p (second g) :when (= (:unit-price p) max-price)] p)})] 124 | (doseq [c categories] (println c)))) 125 | 126 | ;; linq89: Average - Simple 127 | (defn linq89 [] 128 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 129 | avg (average numbers)] 130 | (println "The average number is" avg))) 131 | 132 | ;; linq90: Average - Projection 133 | (defn linq90 [] 134 | (let [words ["cherry", "apple", "blueberry"] 135 | average-length (average (map count words))] 136 | (println "The average word length is" average-length "characters."))) 137 | 138 | ;; linq91: Average - Grouped 139 | (defn linq91 [] 140 | (let [products products-list 141 | categories 142 | (for [g (group-by :category products)] 143 | {:category (first g), 144 | :average-price (average (map :unit-price (second g)))})] 145 | (doseq [c categories] (println c)))) 146 | 147 | ;; linq92: Aggregate - Simple 148 | (defn linq92 [] 149 | (let [dbls [1.7 2.3 1.9 4.1 2.9] 150 | product (reduce * dbls)] 151 | (println "Total product of all numbers:" product))) 152 | 153 | ;; linq93: Aggregate - Seed 154 | (defn linq93 [] 155 | (let [start-balance 100 156 | attempted-withdrawls [20 10 40 50 10 70 30] 157 | end-balance (reduce #(identity (if (<= %2 %1) (- %1 %2) %1)) 158 | start-balance attempted-withdrawls)] 159 | (println "Ending balance:" end-balance))) 160 | 161 | (def examples [linq73 linq74 linq76 linq77 linq78 linq79 linq80 linq81 linq82 linq83 162 | linq84 linq85 linq86 linq87 linq88 linq89 linq90 linq91 linq92 linq93]) 163 | 164 | 165 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 101 LINQ Samples in Clojure 2 | =========================== 3 | 4 | Port of [C#'s' 101 LINQ Samples](http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b) translated into Clojure. 5 | 6 | Compare Clojure to other LINQ examples written in: 7 | 8 | - [#Script lisp](https://sharpscript.net/linq/restriction-operators?lang=lisp) 9 | - [Java](https://github.com/mythz/java-linq-examples) 10 | - [Kotlin](https://github.com/mythz/kotlin-linq-examples) 11 | - [Groovy](https://gitlab.com/svermeulen/groovy-linq-samples) 12 | - [Swift](https://github.com/mythz/swift-linq-examples) 13 | - [Dart](https://github.com/mythz/dart-linq-examples) 14 | - [Elixir](https://github.com/omnibs/elixir-linq-examples) 15 | - [Python](https://github.com/rogerwcpt/python-linq-samples) 16 | - [#Script code](https://sharpscript.net/linq/restriction-operators?lang=code) 17 | 18 | ### Running the examples 19 | 20 | You can choose to run specific examples by commenting the sections you're not interested in [core.clj -main](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/core.clj). 21 | 22 | Execute and display the results of all the examples with: 23 | 24 | lein run 25 | 26 | ### Contents 27 | 28 | The samples below mirrors the C# LINQ samples layout with the names of the top-level Clojure methods matching their corresponding C# examples. 29 | 30 | #### [LINQ - Restriction Operators](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_restrictions.clj) / [MSDN C#](http://code.msdn.microsoft.com/LINQ-to-DataSets-09787825) 31 | #### [LINQ - Projection Operators](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_projections.clj) / [MSDN C#](http://code.msdn.microsoft.com/LINQ-Partitioning-Operators-c68aaccc) 32 | #### [LINQ - Partitioning Operators](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_partitioning.clj) / [MSDN C#](http://code.msdn.microsoft.com/SQL-Ordering-Operators-050af19e) 33 | #### [LINQ - Ordering Operators](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_ordering.clj) / [MSDN C#](http://code.msdn.microsoft.com/SQL-Ordering-Operators-050af19e) 34 | #### [LINQ - Grouping Operators](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_grouping.clj) / [MSDN C#](http://code.msdn.microsoft.com/LINQ-to-DataSets-Grouping-c62703ea) 35 | #### [LINQ - Set Operators](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_setoperators.clj) / [MSDN C#](http://code.msdn.microsoft.com/LINQ-Set-Operators-374f34fe) 36 | #### [LINQ - Conversion Operators](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_conversions.clj) / [MSDN C#](http://code.msdn.microsoft.com/LINQ-Conversion-Operators-e4e59714) 37 | #### [LINQ - Element Operators](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_elementoperators.clj) / [MSDN C#](http://code.msdn.microsoft.com/LINQ-Element-Operators-0f3f12ce) 38 | #### [LINQ - Generation Operators](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_generationoperators.clj) / [MSDN C#](http://code.msdn.microsoft.com/LINQ-Generation-Operators-8a3fbff7) 39 | #### [LINQ - Quantifiers](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_quantifiers.clj) / [MSDN C#](http://code.msdn.microsoft.com/LINQ-Quantifiers-f00e7e3e) 40 | #### [LINQ - Aggregate Operators](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_aggregateoperators.clj) / [MSDN C#](http://code.msdn.microsoft.com/LINQ-Aggregate-Operators-c51b3869) 41 | #### [LINQ - Miscellaneous Operators](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_miscoperators.clj) / [MSDN C#](http://code.msdn.microsoft.com/LINQ-Miscellaneous-6b72bb2a) 42 | #### [LINQ - Query Execution](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_queryexecution.clj) / [MSDN C#](http://code.msdn.microsoft.com/LINQ-Query-Execution-ce0d3b95) 43 | #### [LINQ - Join Operators](https://github.com/mythz/clojure-linq-examples/blob/master/src/clj_linq/linq_joinoperators.clj) / [MSDN C#](http://code.msdn.microsoft.com/LINQ-Join-Operators-dabef4e9) 44 | 45 | ## Side-by-side - C# LINQ vs Clojure 46 | 47 | For a side-by-side comparison, the original **C#** source code is displayed above the equivalent **Clojure** translation. 48 | 49 | - The **Output** shows the console output of running the **Clojure** sample. 50 | - Outputs ending with `...` illustrates only a partial response is displayed. 51 | - The source-code for C# and Clojure utils used are included once under the first section they're used in. 52 | - The C# ObjectDumper util used is downloadable from MSDN - [ObjectDumper.zip](http://code.msdn.microsoft.com/Visual-Studio-2008-C-d295cdba/file/46086/1/ObjectDumper.zip) 53 | 54 | LINQ - Restriction Operators 55 | ---------------------------- 56 | 57 | ### linq1: Where - Simple 1 58 | 59 | ```csharp 60 | //c# 61 | public void Linq1() 62 | { 63 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 64 | 65 | var lowNums = 66 | from n in numbers 67 | where n < 5 68 | select n; 69 | 70 | Console.WriteLine("Numbers < 5:"); 71 | foreach (var x in lowNums) 72 | { 73 | Console.WriteLine(x); 74 | } 75 | } 76 | ``` 77 | ```clojure 78 | ;;clojure 79 | (defn linq1 [] 80 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 81 | low-numbers (filter #(< % 5) numbers)] 82 | (println "Numbers < 5:") 83 | (doseq [n low-numbers] 84 | (println n)))) 85 | ``` 86 | #### Output 87 | 88 | Numbers < 5: 89 | 4 90 | 1 91 | 3 92 | 2 93 | 0 94 | 95 | ### linq2: Where - Simple 2 96 | ```csharp 97 | //c# 98 | public void Linq2() 99 | { 100 | List products = GetProductList(); 101 | 102 | var soldOutProducts = 103 | from p in products 104 | where p.UnitsInStock == 0 105 | select p; 106 | 107 | Console.WriteLine("Sold out products:"); 108 | foreach (var product in soldOutProducts) 109 | { 110 | Console.WriteLine("{0} is sold out!", product.ProductName); 111 | } 112 | } 113 | ``` 114 | ```clojure 115 | ;;clojure 116 | (defn linq2 [] 117 | (let [products products-list 118 | sold-out-products (for [p products 119 | :when (= 0 (:units-in-stock p))] 120 | p)] 121 | (println "Sold out products:") 122 | (doseq [p sold-out-products] 123 | (println (:product-name p) " is sold out")))) 124 | ``` 125 | #### Output 126 | 127 | Sold out products: 128 | Chef Anton's Gumbo Mix is sold out 129 | Alice Mutton is sold out 130 | Thüringer Rostbratwurst is sold out 131 | Gorgonzola Telino is sold out 132 | Perth Pasties is sold out 133 | 134 | ### linq3: Where - Simple 3 135 | ```csharp 136 | //c# 137 | public void Linq3() 138 | { 139 | List products = GetProductList(); 140 | 141 | var expensiveInStockProducts = 142 | from p in products 143 | where p.UnitsInStock > 0 && p.UnitPrice > 3.00M 144 | select p; 145 | 146 | Console.WriteLine("In-stock products that cost more than 3.00:"); 147 | foreach (var product in expensiveInStockProducts) 148 | { 149 | Console.WriteLine("{0} is in stock and costs more than 3.00.", product.ProductName); 150 | } 151 | } 152 | ``` 153 | ```clojure 154 | ;;clojure 155 | (defn linq3 [] 156 | (let [products products-list 157 | expensive-in-stock-products 158 | (for [p products-list 159 | :when (and 160 | (> (:units-in-stock p) 0) 161 | (> (:unit-price p) 3))] 162 | p)] 163 | (println "In-stock products that cost more than 3.00:") 164 | (doseq [p expensive-in-stock-products] 165 | (println (:product-name p) "is in stock and costs more than 3.00")))) 166 | ``` 167 | #### Output 168 | 169 | In-stock products that cost more than 3.00: 170 | Chai is in stock and costs more than 3.00 171 | Chang is in stock and costs more than 3.00 172 | Aniseed Syrup is in stock and costs more than 3.00 173 | Chef Anton's Cajun Seasoning is in stock and costs more than 3.00 174 | Grandma's Boysenberry Spread is in stock and costs more than 3.00 175 | 176 | ### linq4: Where - Drilldown 177 | ```csharp 178 | //c# 179 | public void Linq4() 180 | { 181 | List customers = GetCustomerList(); 182 | 183 | var waCustomers = 184 | from c in customers 185 | where c.Region == "WA" 186 | select c; 187 | 188 | Console.WriteLine("Customers from Washington and their orders:"); 189 | foreach (var customer in waCustomers) 190 | { 191 | Console.WriteLine("Customer {0}: {1}", customer.CustomerID, customer.CompanyName); 192 | foreach (var order in customer.Orders) 193 | { 194 | Console.WriteLine(" Order {0}: {1}", order.OrderID, order.OrderDate); 195 | } 196 | } 197 | } 198 | ``` 199 | ```clojure 200 | ;;clojure 201 | (defn linq4 [] 202 | (let [customers customers-list 203 | wa-customers (filter #(= (:region %) "WA") customers)] 204 | (println "Customers from Washington and their orders:") 205 | (doseq [c wa-customers] 206 | (println "Customer" (:customer-id c) ": " (:company-name c) ":") 207 | (doseq [o (:orders c)] 208 | (println " Order" (:order-id o) ":" (:order-date o)))))) 209 | ``` 210 | #### Output 211 | 212 | Customers from Washington and their orders: 213 | Customer LAZYK : Lazy K Kountry Store : 214 | Order 10482 : # 215 | Order 10545 : # 216 | Customer TRAIH : Trail's Head Gourmet Provisioners : 217 | Order 10574 : # 218 | Order 10577 : # 219 | Order 10822 : # 220 | ... 221 | 222 | ### linq5: Where - Indexed 223 | ```csharp 224 | //c# 225 | public void Linq5() 226 | { 227 | string[] digits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; 228 | 229 | var shortDigits = digits.Where((digit, index) => digit.Length < index); 230 | 231 | Console.WriteLine("Short digits:"); 232 | foreach (var d in shortDigits) 233 | { 234 | Console.WriteLine("The word {0} is shorter than its value.", d); 235 | } 236 | } 237 | ``` 238 | ```clojure 239 | ;;clojure 240 | (defn linq5 [] 241 | (let [digits ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"] 242 | short-digits 243 | (for [[i digit] (map-indexed vector digits) 244 | :when (> i (count digit))] 245 | digit)] 246 | (println "Short digits:") 247 | (doseq [d short-digits] 248 | (println "The word" d "is shorter than its value")))) 249 | ``` 250 | #### Output 251 | 252 | Short digits: 253 | The word five is shorter than its value 254 | The word six is shorter than its value 255 | The word seven is shorter than its value 256 | The word eight is shorter than its value 257 | The word nine is shorter than its value 258 | 259 | 260 | LINQ - Projection Operators 261 | --------------------------- 262 | 263 | ### linq6: Select - Simple 1 264 | ```csharp 265 | //c# 266 | public void Linq6() 267 | { 268 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 269 | 270 | var numsPlusOne = 271 | from n in numbers 272 | select n + 1; 273 | 274 | Console.WriteLine("Numbers + 1:"); 275 | foreach (var i in numsPlusOne) 276 | { 277 | Console.WriteLine(i); 278 | } 279 | } 280 | ``` 281 | ```clojure 282 | ;;clojure 283 | (defn linq6 [] 284 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 285 | nums-plus-one (map inc numbers)] 286 | (println "Numbers + 1:") 287 | (doseq [n nums-plus-one] (println n)))) 288 | ``` 289 | #### Output 290 | 291 | Numbers + 1: 292 | 6 293 | 5 294 | 2 295 | 4 296 | 10 297 | 9 298 | 7 299 | 8 300 | 3 301 | 1 302 | 303 | ### linq7: Select - Simple 2 304 | ```csharp 305 | //c# 306 | public void Linq7() 307 | { 308 | List products = GetProductList(); 309 | 310 | var productNames = 311 | from p in products 312 | select p.ProductName; 313 | 314 | Console.WriteLine("Product Names:"); 315 | foreach (var productName in productNames) 316 | { 317 | Console.WriteLine(productName); 318 | } 319 | } 320 | ``` 321 | ```clojure 322 | ;;clojure 323 | (defn linq7 [] 324 | (let [products products-list 325 | product-names (map #(:product-name %) products)] 326 | (println "Product Names:") 327 | (doseq [x product-names] (println x)))) 328 | ``` 329 | #### Output 330 | 331 | Product Names: 332 | Chai 333 | Chang 334 | Aniseed Syrup 335 | Chef Anton's Cajun Seasoning 336 | Chef Anton's Gumbo Mix 337 | ... 338 | 339 | ### linq8: Select - Transformation 340 | ```csharp 341 | //c# 342 | public void Linq8() 343 | { 344 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 345 | string[] strings = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; 346 | 347 | var textNums = 348 | from n in numbers 349 | select strings[n]; 350 | 351 | Console.WriteLine("Number strings:"); 352 | foreach (var s in textNums) 353 | { 354 | Console.WriteLine(s); 355 | } 356 | } 357 | ``` 358 | ```clojure 359 | ;;clojure 360 | (defn linq8 [] 361 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 362 | strings ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"] 363 | text-nums (map strings numbers)] 364 | (println "Number strings:") 365 | (doseq [n text-nums] (println n)))) 366 | ``` 367 | #### Output 368 | 369 | Number strings: 370 | five 371 | four 372 | one 373 | three 374 | nine 375 | eight 376 | six 377 | seven 378 | two 379 | zero 380 | 381 | ### linq9: Select - Anonymous Types 1 382 | ```csharp 383 | //c# 384 | public void Linq9() 385 | { 386 | string[] words = { "aPPLE", "BlUeBeRrY", "cHeRry" }; 387 | 388 | var upperLowerWords = 389 | from w in words 390 | select new { Upper = w.ToUpper(), Lower = w.ToLower() }; 391 | 392 | foreach (var ul in upperLowerWords) 393 | { 394 | Console.WriteLine("Uppercase: {0}, Lowercase: {1}", ul.Upper, ul.Lower); 395 | } 396 | } 397 | ``` 398 | ```clojure 399 | ;;clojure 400 | (defn linq9 [] 401 | (let [words ["aPPLE", "BlUeBeRrY", "cHeRry"] 402 | upper-lower-words 403 | (for [w words] { :lower (str/lower-case w), :upper (str/upper-case w)})] 404 | (doseq [ul upper-lower-words] 405 | (println "Uppercase:" (:upper ul) ", Lowercase:" (:lower ul))))) 406 | ``` 407 | #### Output 408 | 409 | Uppercase: APPLE , Lowercase: apple 410 | Uppercase: BLUEBERRY , Lowercase: blueberry 411 | Uppercase: CHERRY , Lowercase: cherry 412 | 413 | ### linq10: Select - Anonymous Types 2 414 | ```csharp 415 | //c# 416 | public void Linq10() 417 | { 418 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 419 | string[] strings = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; 420 | 421 | var digitOddEvens = 422 | from n in numbers 423 | select new { Digit = strings[n], Even = (n % 2 == 0) }; 424 | 425 | foreach (var d in digitOddEvens) 426 | { 427 | Console.WriteLine("The digit {0} is {1}.", d.Digit, d.Even ? "even" : "odd"); 428 | } 429 | } 430 | ``` 431 | ```clojure 432 | ;;clojure 433 | (defn linq10 [] 434 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 435 | strings ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"] 436 | digit-odd-evens 437 | (for [n numbers] {:digit (strings n), :even (= (mod n 2) 0)})] 438 | (doseq [d digit-odd-evens] 439 | (println "The digit" (:digit d) "is" (if (:even d) "even" "odd"))))) 440 | ``` 441 | #### Output 442 | 443 | The digit five is odd 444 | The digit four is even 445 | The digit one is odd 446 | The digit three is odd 447 | The digit nine is odd 448 | The digit eight is even 449 | The digit six is even 450 | The digit seven is odd 451 | The digit two is even 452 | The digit zero is even 453 | 454 | ### linq11: Select - Anonymous Types 3 455 | ```csharp 456 | //c# 457 | public void Linq11() 458 | { 459 | List products = GetProductList(); 460 | 461 | var productInfos = 462 | from p in products 463 | select new { p.ProductName, p.Category, Price = p.UnitPrice }; 464 | 465 | Console.WriteLine("Product Info:"); 466 | foreach (var productInfo in productInfos) 467 | { 468 | Console.WriteLine("{0} is in the category {1} and costs {2} per unit.", productInfo.ProductName, productInfo.Category, productInfo.Price); 469 | } 470 | } 471 | ``` 472 | ```clojure 473 | ;;clojure 474 | (defn linq11 [] 475 | (let [products products-list 476 | product-infos 477 | (for [p products] 478 | {:product-name (:product-name p), 479 | :category (:category p), 480 | :price (:unit-price p)})] 481 | (println "Product Info:") 482 | (doseq [p product-infos] 483 | (println (:product-name p) "is in the category" (:category p) 484 | "and costs" (:price p))))) 485 | ``` 486 | #### Output 487 | 488 | Product Info: 489 | Chai is in the category Beverages and costs 18.0 490 | Chang is in the category Beverages and costs 19.0 491 | Aniseed Syrup is in the category Condiments and costs 10.0 492 | ... 493 | 494 | ### linq12: Select - Indexed 495 | ```csharp 496 | //c# 497 | public void Linq12() 498 | { 499 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 500 | 501 | var numsInPlace = numbers.Select((num, index) => new { Num = num, InPlace = (num == index) }); 502 | 503 | Console.WriteLine("Number: In-place?"); 504 | foreach (var n in numsInPlace) 505 | { 506 | Console.WriteLine("{0}: {1}", n.Num, n.InPlace); 507 | } 508 | } 509 | ``` 510 | ```clojure 511 | ;;clojure 512 | (defn linq12 [] 513 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 514 | nums-in-place 515 | (map-indexed (fn [i num] {:num num, :in-place (= num i)}) numbers)] 516 | (println "Number: In-place?") 517 | (doseq [n nums-in-place] 518 | (println (:num n) ":" (:in-place n))))) 519 | ``` 520 | #### Output 521 | 522 | Number: In-place? 523 | 5 : false 524 | 4 : false 525 | 1 : false 526 | 3 : true 527 | 9 : false 528 | 8 : false 529 | 6 : true 530 | 7 : true 531 | 2 : false 532 | 0 : false 533 | 534 | ### linq13: Select - Filtered 535 | ```csharp 536 | //c# 537 | public void Linq13() 538 | { 539 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 540 | string[] digits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; 541 | 542 | var lowNums = 543 | from n in numbers 544 | where n < 5 545 | select digits[n]; 546 | 547 | Console.WriteLine("Numbers < 5:"); 548 | foreach (var num in lowNums) 549 | { 550 | Console.WriteLine(num); 551 | } 552 | } 553 | ``` 554 | ```clojure 555 | ;;clojure 556 | (defn linq13 [] 557 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 558 | digits ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"] 559 | low-nums (for [n numbers 560 | :when (< n 5)] 561 | (digits n))] 562 | (println "Numbers < 5:") 563 | (doseq [n low-nums] (println n)))) 564 | ``` 565 | #### Output 566 | 567 | Numbers < 5: 568 | four 569 | one 570 | three 571 | two 572 | zero 573 | 574 | ### linq14: SelectMany - Compound from 1 575 | ```csharp 576 | //c# 577 | public void Linq14() 578 | { 579 | int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 }; 580 | int[] numbersB = { 1, 3, 5, 7, 8 }; 581 | 582 | var pairs = 583 | from a in numbersA 584 | from b in numbersB 585 | where a < b 586 | select new { a, b }; 587 | 588 | Console.WriteLine("Pairs where a < b:"); 589 | foreach (var pair in pairs) 590 | { 591 | Console.WriteLine("{0} is less than {1}", pair.a, pair.b); 592 | } 593 | } 594 | ``` 595 | ```clojure 596 | ;;clojure 597 | (defn linq14 [] 598 | (let [numbers-a [0 2 4 5 6 8 9] 599 | numbers-b [1 3 5 7 8] 600 | pairs (for [a numbers-a 601 | b numbers-b 602 | :when (< a b)] 603 | {:a a, :b b})] 604 | (println "Pairs where a < b:") 605 | (doseq [pair pairs] 606 | (println (:a pair) "is less than" (:b pair))))) 607 | ``` 608 | #### Output 609 | 610 | Pairs where a < b: 611 | 0 is less than 1 612 | 0 is less than 3 613 | 0 is less than 5 614 | 0 is less than 7 615 | 0 is less than 8 616 | 2 is less than 3 617 | 2 is less than 5 618 | 2 is less than 7 619 | 2 is less than 8 620 | 4 is less than 5 621 | 4 is less than 7 622 | 4 is less than 8 623 | 5 is less than 7 624 | 5 is less than 8 625 | 6 is less than 7 626 | 6 is less than 8 627 | 628 | ### linq15: SelectMany - Compound from 2 629 | ```csharp 630 | //c# 631 | public void Linq15() 632 | { 633 | List customers = GetCustomerList(); 634 | 635 | var orders = 636 | from c in customers 637 | from o in c.Orders 638 | where o.Total < 500.00M 639 | select new { c.CustomerID, o.OrderID, o.Total }; 640 | 641 | ObjectDumper.Write(orders); 642 | } 643 | ``` 644 | ```clojure 645 | ;;clojure 646 | (defn linq15 [] 647 | (let [customers customers-list 648 | orders 649 | (for [c customers 650 | o (:orders c) 651 | :when (< (:total o) 500)] 652 | {:customer-id (:customer-id c), 653 | :order-id (:order-id o), 654 | :total (:total o)})] 655 | (doseq [o orders] (println o)))) 656 | ``` 657 | #### Output 658 | 659 | {:customer-id ALFKI, :order-id 10702, :total 330.00M} 660 | {:customer-id ALFKI, :order-id 10952, :total 471.20M} 661 | {:customer-id ANATR, :order-id 10308, :total 88.80M} 662 | {:customer-id ANATR, :order-id 10625, :total 479.75M} 663 | ... 664 | 665 | ### linq16: SelectMany - Compound from 3 666 | ```csharp 667 | //c# 668 | public void Linq16() 669 | { 670 | List customers = GetCustomerList(); 671 | 672 | var orders = 673 | from c in customers 674 | from o in c.Orders 675 | where o.OrderDate >= new DateTime(1998, 1, 1) 676 | select new { c.CustomerID, o.OrderID, o.OrderDate }; 677 | 678 | ObjectDumper.Write(orders); 679 | } 680 | ``` 681 | ```clojure 682 | ;;clojure 683 | (defn linq16 [] 684 | (let [customers customers-list 685 | orders 686 | (for [c customers 687 | o (:orders c) 688 | :when (time/after? (:order-date o) (time/date-time 1998 1 1))] 689 | {:customer-id (:customer-id c), 690 | :order-id (:order-id o), 691 | :order-date (:order-date o)})] 692 | (doseq [o orders] (println o)))) 693 | ``` 694 | #### Output 695 | 696 | {:customer-id ALFKI, :order-id 10835, :order-date #} 697 | {:customer-id ALFKI, :order-id 10952, :order-date #} 698 | {:customer-id ALFKI, :order-id 11011, :order-date #} 699 | {:customer-id ANATR, :order-id 10926, :order-date #} 700 | {:customer-id ANTON, :order-id 10856, :order-date #} 701 | ... 702 | 703 | ### linq17: SelectMany - from Assignment 704 | ```csharp 705 | //c# 706 | public void Linq17() 707 | { 708 | List customers = GetCustomerList(); 709 | 710 | var orders = 711 | from c in customers 712 | from o in c.Orders 713 | where o.Total >= 2000.0M 714 | select new { c.CustomerID, o.OrderID, o.Total }; 715 | 716 | ObjectDumper.Write(orders); 717 | } 718 | ``` 719 | ```clojure 720 | ;;clojure 721 | (defn linq17 [] 722 | (let [customers customers-list 723 | orders 724 | (for [c customers 725 | o (:orders c) 726 | :when (>= (:total o) 2000)] 727 | {:customer-id (:customer-id c), :order-id (:order-id o), :total (:total o)})] 728 | (doseq [o orders] (println o)))) 729 | ``` 730 | #### Output 731 | 732 | {:customer-id ANTON, :order-id 10573, :total 2082.00M} 733 | {:customer-id AROUT, :order-id 10558, :total 2142.90M} 734 | {:customer-id AROUT, :order-id 10953, :total 4441.25M} 735 | {:customer-id BERGS, :order-id 10384, :total 2222.40M} 736 | {:customer-id BERGS, :order-id 10524, :total 3192.65M} 737 | ... 738 | 739 | ### linq18: SelectMany - Multiple from 740 | ```csharp 741 | //c# 742 | public void Linq18() 743 | { 744 | List customers = GetCustomerList(); 745 | 746 | DateTime cutoffDate = new DateTime(1997, 1, 1); 747 | 748 | var orders = 749 | from c in customers 750 | where c.Region == "WA" 751 | from o in c.Orders 752 | where o.OrderDate >= cutoffDate 753 | select new { c.CustomerID, o.OrderID }; 754 | 755 | ObjectDumper.Write(orders); 756 | } 757 | ``` 758 | ```clojure 759 | ;;clojure 760 | (defn linq18 [] 761 | (let [customers customers-list 762 | cutoff-date (time/date-time 1997 1 1) 763 | orders 764 | (for [c customers 765 | :when (= (:region c) "WA") 766 | o (:orders c) 767 | :when (time/after? (:order-date o) cutoff-date)] 768 | {:customer-id (:customer-id c), :order-id (:order-id o)})] 769 | (doseq [o orders] (println o)))) 770 | ``` 771 | #### Output 772 | 773 | {:customer-id LAZYK, :order-id 10482} 774 | {:customer-id LAZYK, :order-id 10545} 775 | {:customer-id TRAIH, :order-id 10574} 776 | {:customer-id TRAIH, :order-id 10577} 777 | {:customer-id TRAIH, :order-id 10822} 778 | {:customer-id WHITC, :order-id 10469} 779 | {:customer-id WHITC, :order-id 10483} 780 | {:customer-id WHITC, :order-id 10504} 781 | {:customer-id WHITC, :order-id 10596} 782 | {:customer-id WHITC, :order-id 10693} 783 | {:customer-id WHITC, :order-id 10696} 784 | {:customer-id WHITC, :order-id 10723} 785 | {:customer-id WHITC, :order-id 10740} 786 | {:customer-id WHITC, :order-id 10861} 787 | {:customer-id WHITC, :order-id 10904} 788 | {:customer-id WHITC, :order-id 11032} 789 | {:customer-id WHITC, :order-id 11066} 790 | 791 | ### linq19: SelectMany - Indexed 792 | ```csharp 793 | //c# 794 | public void Linq19() 795 | { 796 | List customers = GetCustomerList(); 797 | 798 | var customerOrders = 799 | customers.SelectMany( 800 | (cust, custIndex) => 801 | cust.Orders.Select(o => "Customer #" + (custIndex + 1) + 802 | " has an order with OrderID " + o.OrderID)); 803 | 804 | ObjectDumper.Write(customerOrders); 805 | } 806 | ``` 807 | ```clojure 808 | ;;clojure 809 | (defn linq19 [] 810 | (let [customers customers-list 811 | customer-orders 812 | (for [[i c] (map-indexed vector customers) 813 | o (:orders c)] 814 | (str "Customer #" (inc i) " has an order with OrderID " (:order-id o)))] 815 | (doseq [x customer-orders] (println x)))) 816 | ``` 817 | #### Output 818 | 819 | Customer #1 has an order with OrderID 10643 820 | Customer #1 has an order with OrderID 10692 821 | Customer #1 has an order with OrderID 10702 822 | Customer #1 has an order with OrderID 10835 823 | Customer #1 has an order with OrderID 10952 824 | Customer #1 has an order with OrderID 11011 825 | Customer #2 has an order with OrderID 10308 826 | Customer #2 has an order with OrderID 10625 827 | Customer #2 has an order with OrderID 10759 828 | Customer #2 has an order with OrderID 10926 829 | ... 830 | 831 | LINQ - Partitioning Operators 832 | ----------------------------- 833 | 834 | ### linq20: Take - Simple 835 | ```csharp 836 | //c# 837 | public void Linq20() 838 | { 839 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 840 | 841 | var first3Numbers = numbers.Take(3); 842 | 843 | Console.WriteLine("First 3 numbers:"); 844 | 845 | foreach (var n in first3Numbers) 846 | { 847 | Console.WriteLine(n); 848 | } 849 | } 850 | ``` 851 | ```clojure 852 | ;;clojure 853 | (defn linq20 [] 854 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 855 | first-3-numbers (take 3 numbers)] 856 | (println "First 3 numbers:") 857 | (doseq [n first-3-numbers] (println n)))) 858 | ``` 859 | #### Output 860 | 861 | First 3 numbers: 862 | 5 863 | 4 864 | 1 865 | 866 | ### linq21: Take - Nested 867 | ```csharp 868 | //c# 869 | public void Linq21() 870 | { 871 | List customers = GetCustomerList(); 872 | 873 | var first3WAOrders = ( 874 | from c in customers 875 | from o in c.Orders 876 | where c.Region == "WA" 877 | select new { c.CustomerID, o.OrderID, o.OrderDate }) 878 | .Take(3); 879 | 880 | Console.WriteLine("First 3 orders in WA:"); 881 | foreach (var order in first3WAOrders) 882 | { 883 | ObjectDumper.Write(order); 884 | } 885 | } 886 | ``` 887 | ```clojure 888 | ;;clojure 889 | (defn linq21 [] 890 | (let [customers customers-list 891 | first-3-wa-orders 892 | (take 3 893 | (for [c customers 894 | :when (= (:region c) "WA") 895 | o (:orders c)] 896 | {:customer-id (:customer-id c), 897 | :order-id (:order-id o), 898 | :order-date (:order-date o)}))] 899 | (println "First 3 orders in WA:") 900 | (doseq [x first-3-wa-orders] (println x)))) 901 | ``` 902 | #### Output 903 | 904 | First 3 orders in WA: 905 | {:customer-id LAZYK, :order-id 10482, :order-date #} 906 | {:customer-id LAZYK, :order-id 10545, :order-date #} 907 | {:customer-id TRAIH, :order-id 10574, :order-date #} 908 | 909 | ### linq22: Skip - Simple 910 | ```csharp 911 | //c# 912 | public void Linq22() 913 | { 914 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 915 | 916 | var allButFirst4Numbers = numbers.Skip(4); 917 | 918 | Console.WriteLine("All but first 4 numbers:"); 919 | foreach (var n in allButFirst4Numbers) 920 | { 921 | Console.WriteLine(n); 922 | } 923 | } 924 | ``` 925 | ```clojure 926 | ;;clojure 927 | (defn linq22 [] 928 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 929 | all-but-first-4-numbers (drop 4 numbers)] 930 | (println "All but first 4 numbers:") 931 | (doseq [n all-but-first-4-numbers] (println n)))) 932 | ``` 933 | #### Output 934 | 935 | All but first 4 numbers: 936 | 9 937 | 8 938 | 6 939 | 7 940 | 2 941 | 0 942 | 943 | ### linq23: Skip - Nested 944 | ```csharp 945 | //c# 946 | public void Linq23() 947 | { 948 | List customers = GetCustomerList(); 949 | 950 | var waOrders = 951 | from c in customers 952 | from o in c.Orders 953 | where c.Region == "WA" 954 | select new { c.CustomerID, o.OrderID, o.OrderDate }; 955 | 956 | var allButFirst2Orders = waOrders.Skip(2); 957 | 958 | Console.WriteLine("All but first 2 orders in WA:"); 959 | foreach (var order in allButFirst2Orders) 960 | { 961 | ObjectDumper.Write(order); 962 | } 963 | } 964 | ``` 965 | ```clojure 966 | ;;clojure 967 | (defn linq23 [] 968 | (let [customers customers-list 969 | all-but-first-2-orders 970 | (drop 2 971 | (for [c customers 972 | :when (= (:region c) "WA") 973 | o (:orders c)] 974 | {:customer-id (:customer-id c), 975 | :order-id (:order-id o), 976 | :order-date (:order-date o)}))] 977 | (println "All but first 2 orders in WA:") 978 | (doseq [o all-but-first-2-orders] (println o)))) 979 | ``` 980 | #### Output 981 | 982 | All but first 2 orders in WA: 983 | {:customer-id TRAIH, :order-id 10574, :order-date #} 984 | {:customer-id TRAIH, :order-id 10577, :order-date #} 985 | {:customer-id TRAIH, :order-id 10822, :order-date #} 986 | {:customer-id WHITC, :order-id 10269, :order-date #} 987 | {:customer-id WHITC, :order-id 10344, :order-date #} 988 | {:customer-id WHITC, :order-id 10469, :order-date #} 989 | {:customer-id WHITC, :order-id 10483, :order-date #} 990 | {:customer-id WHITC, :order-id 10504, :order-date #} 991 | {:customer-id WHITC, :order-id 10596, :order-date #} 992 | {:customer-id WHITC, :order-id 10693, :order-date #} 993 | {:customer-id WHITC, :order-id 10696, :order-date #} 994 | {:customer-id WHITC, :order-id 10723, :order-date #} 995 | {:customer-id WHITC, :order-id 10740, :order-date #} 996 | {:customer-id WHITC, :order-id 10861, :order-date #} 997 | {:customer-id WHITC, :order-id 10904, :order-date #} 998 | {:customer-id WHITC, :order-id 11032, :order-date #} 999 | {:customer-id WHITC, :order-id 11066, :order-date #} 1000 | 1001 | ### linq24: TakeWhile - Simple 1002 | ```csharp 1003 | //c# 1004 | public void Linq24() 1005 | { 1006 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 1007 | 1008 | var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6); 1009 | 1010 | Console.WriteLine("First numbers less than 6:"); 1011 | foreach (var n in firstNumbersLessThan6) 1012 | { 1013 | Console.WriteLine(n); 1014 | } 1015 | } 1016 | ``` 1017 | ```clojure 1018 | ;;clojure 1019 | (defn linq24 [] 1020 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 1021 | first-numbers-less-than-6 (take-while #(< % 6) numbers)] 1022 | (println "First numbers less than 6:") 1023 | (doseq [n first-numbers-less-than-6] (println n)))) 1024 | ``` 1025 | #### Output 1026 | 1027 | First numbers less than 6: 1028 | 5 1029 | 4 1030 | 1 1031 | 3 1032 | 1033 | ### linq25: TakeWhile - Indexed 1034 | ```csharp 1035 | //c# 1036 | public void Linq25() 1037 | { 1038 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 1039 | 1040 | var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index); 1041 | 1042 | Console.WriteLine("First numbers not less than their position:"); 1043 | foreach (var n in firstSmallNumbers) 1044 | { 1045 | Console.WriteLine(n); 1046 | } 1047 | } 1048 | ``` 1049 | ```clojure 1050 | ;;clojure 1051 | (defn linq25 [] 1052 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 1053 | first-small-numbers 1054 | (for [[i num] (map-indexed vector numbers) 1055 | :while (>= num i)] 1056 | num)] 1057 | (println "First numbers not less than their position:") 1058 | (doseq [n first-small-numbers] (println n)))) 1059 | ``` 1060 | #### Output 1061 | 1062 | First numbers not less than their position: 1063 | 5 1064 | 4 1065 | 1066 | ### linq26: SkipWhile - Simple 1067 | ```csharp 1068 | //c# 1069 | public void Linq26() 1070 | { 1071 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 1072 | 1073 | var allButFirst3Numbers = numbers.SkipWhile(n => n % 3 != 0); 1074 | 1075 | Console.WriteLine("All elements starting from first element divisible by 3:"); 1076 | foreach (var n in allButFirst3Numbers) 1077 | { 1078 | Console.WriteLine(n); 1079 | } 1080 | } 1081 | ``` 1082 | ```clojure 1083 | ;;clojure 1084 | (defn linq26 [] 1085 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 1086 | all-but-first-3-numbers (drop-while #(not= (mod % 3) 0) numbers)] 1087 | (println "All elements starting from first element divisible by 3:") 1088 | (doseq [n all-but-first-3-numbers] (println n)))) 1089 | ``` 1090 | #### Output 1091 | 1092 | All elements starting from first element divisible by 3: 1093 | 3 1094 | 9 1095 | 8 1096 | 6 1097 | 7 1098 | 2 1099 | 0 1100 | 1101 | ### linq27: SkipWhile - Indexed 1102 | ```csharp 1103 | //c# 1104 | public void Linq27() 1105 | { 1106 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 1107 | 1108 | var laterNumbers = numbers.SkipWhile((n, index) => n >= index); 1109 | 1110 | Console.WriteLine("All elements starting from first element less than its position:"); 1111 | foreach (var n in laterNumbers) 1112 | { 1113 | Console.WriteLine(n); 1114 | } 1115 | } 1116 | ``` 1117 | ```clojure 1118 | ;;clojure 1119 | (defn linq27 [] 1120 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 1121 | later-numbers 1122 | (map (fn [[i num]] num) 1123 | (drop-while (fn [[i num]] (>= num i)) (map-indexed vector numbers)))] 1124 | (println "All elements starting from first element less than its position:") 1125 | (doseq [n later-numbers] (println n)))) 1126 | ``` 1127 | #### Output 1128 | 1129 | All elements starting from first element less than its position: 1130 | 1 1131 | 3 1132 | 9 1133 | 8 1134 | 6 1135 | 7 1136 | 2 1137 | 0 1138 | 1139 | 1140 | LINQ - Ordering Operators 1141 | ------------------------- 1142 | 1143 | ### C# utils added 1144 | 1145 | ```csharp 1146 | public class CaseInsensitiveComparer : IComparer 1147 | { 1148 | public int Compare(string x, string y) 1149 | { 1150 | return string.Compare(x, y, StringComparison.OrdinalIgnoreCase); 1151 | } 1152 | } 1153 | ``` 1154 | 1155 | ### Clojure utils added 1156 | 1157 | ```clojure 1158 | (defn case-insensitive-compare [s1 s2] 1159 | (compare (.toLowerCase s1) (.toLowerCase s2))) 1160 | 1161 | (defn order-by-comparers [comparers xs] 1162 | (sort-by 1163 | pass-thru 1164 | (fn [a1 a2] 1165 | (nth (for [x (map #(% a1 a2) comparers) 1166 | :when (not= x 0)] x) 1167 | 0 0)) 1168 | xs)) 1169 | 1170 | (defn order-by [fns xs] 1171 | (sort-by (apply juxt fns) xs)) 1172 | ``` 1173 | 1174 | ### linq28: OrderBy - Simple 1 1175 | ```csharp 1176 | //c# 1177 | public void Linq28() 1178 | { 1179 | string[] words = { "cherry", "apple", "blueberry" }; 1180 | 1181 | var sortedWords = 1182 | from w in words 1183 | orderby w 1184 | select w; 1185 | 1186 | Console.WriteLine("The sorted list of words:"); 1187 | foreach (var w in sortedWords) 1188 | { 1189 | Console.WriteLine(w); 1190 | } 1191 | } 1192 | ``` 1193 | ```clojure 1194 | ;;clojure 1195 | (defn linq28 [] 1196 | (let [words ["cherry" "apple" "blueberry"] 1197 | sorted-words (sort words)] 1198 | (println "The sorted list of words:") 1199 | (doseq [w sorted-words] (println w)))) 1200 | ``` 1201 | #### Output 1202 | 1203 | The sorted list of words: 1204 | apple 1205 | blueberry 1206 | cherry 1207 | 1208 | ### linq29: OrderBy - Simple 2 1209 | ```csharp 1210 | //c# 1211 | public void Linq29() 1212 | { 1213 | string[] words = { "cherry", "apple", "blueberry" }; 1214 | 1215 | var sortedWords = 1216 | from w in words 1217 | orderby w.Length 1218 | select w; 1219 | 1220 | Console.WriteLine("The sorted list of words (by length):"); 1221 | foreach (var w in sortedWords) 1222 | { 1223 | Console.WriteLine(w); 1224 | } 1225 | } 1226 | ``` 1227 | ```clojure 1228 | ;;clojure 1229 | (defn linq29 [] 1230 | (let [words ["cherry" "apple" "blueberry"] 1231 | sorted-words (sort-by count words)] 1232 | (println "The sorted list of words (by length):") 1233 | (doseq [w sorted-words] (println w)))) 1234 | ``` 1235 | #### Output 1236 | 1237 | The sorted list of words (by length): 1238 | apple 1239 | cherry 1240 | blueberry 1241 | 1242 | ### linq30: OrderBy - Simple 3 1243 | ```csharp 1244 | //c# 1245 | public void Linq30() 1246 | { 1247 | List products = GetProductList(); 1248 | 1249 | var sortedProducts = 1250 | from p in products 1251 | orderby p.ProductName 1252 | select p; 1253 | 1254 | ObjectDumper.Write(sortedProducts); 1255 | } 1256 | ``` 1257 | ```clojure 1258 | ;;clojure 1259 | (defn linq30 [] 1260 | (let [products products-list 1261 | sorted-products (sort-by :product-name products)] 1262 | (doseq [p sorted-products] (println p)))) 1263 | ``` 1264 | #### Output 1265 | 1266 | #clj_linq.data.Product{:product-id 17, :product-name Alice Mutton, :category Meat/Poultry, :unit-price 39.0, :units-in-stock 0} 1267 | #clj_linq.data.Product{:product-id 3, :product-name Aniseed Syrup, :category Condiments, :unit-price 10.0, :units-in-stock 13} 1268 | #clj_linq.data.Product{:product-id 40, :product-name Boston Crab Meat, :category Seafood, :unit-price 18.4, :units-in-stock 123} 1269 | #clj_linq.data.Product{:product-id 60, :product-name Camembert Pierrot, :category Dairy Products, :unit-price 34.0, :units-in-stock 19} 1270 | #clj_linq.data.Product{:product-id 18, :product-name Carnarvon Tigers, :category Seafood, :unit-price 62.5, :units-in-stock 42} 1271 | ... 1272 | 1273 | ### linq31: OrderBy - Comparer 1274 | ```csharp 1275 | //c# 1276 | public void Linq31() 1277 | { 1278 | string[] words = { "aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr", "cHeRry" }; 1279 | 1280 | var sortedWords = words.OrderBy(a => a, new CaseInsensitiveComparer()); 1281 | 1282 | ObjectDumper.Write(sortedWords); 1283 | } 1284 | ``` 1285 | ```clojure 1286 | ;;clojure 1287 | (defn linq31 [] 1288 | (let [words ["aPPLE" "AbAcUs" "bRaNcH" "BlUeBeRrY" "ClOvEr" "cHeRry"] 1289 | sorted-words (sort-by identity case-insensitive-compare words)] 1290 | (doseq [w sorted-words] (println w)))) 1291 | ``` 1292 | #### Output 1293 | 1294 | AbAcUs 1295 | aPPLE 1296 | BlUeBeRrY 1297 | bRaNcH 1298 | cHeRry 1299 | ClOvEr 1300 | 1301 | ### linq32: OrderByDescending - Simple 1 1302 | ```csharp 1303 | //c# 1304 | public void Linq32() 1305 | { 1306 | double[] doubles = { 1.7, 2.3, 1.9, 4.1, 2.9 }; 1307 | 1308 | var sortedDoubles = 1309 | from d in doubles 1310 | orderby d descending 1311 | select d; 1312 | 1313 | Console.WriteLine("The doubles from highest to lowest:"); 1314 | foreach (var d in sortedDoubles) 1315 | { 1316 | Console.WriteLine(d); 1317 | } 1318 | } 1319 | ``` 1320 | ```clojure 1321 | ;;clojure 1322 | (defn linq32 [] 1323 | (let [dbls [1.7 2.3 1.9 4.1 2.9] 1324 | sorted-doubles (reverse (sort dbls))] 1325 | (println "The doubles from highest to lowest:") 1326 | (doseq [d sorted-doubles] (println d)))) 1327 | ``` 1328 | #### Output 1329 | 1330 | The doubles from highest to lowest: 1331 | 4.1 1332 | 2.9 1333 | 2.3 1334 | 1.9 1335 | 1.7 1336 | 1337 | ### linq33: OrderByDescending - Simple 2 1338 | ```csharp 1339 | //c# 1340 | public void Linq33() 1341 | { 1342 | List products = GetProductList(); 1343 | 1344 | var sortedProducts = 1345 | from p in products 1346 | orderby p.UnitsInStock descending 1347 | select p; 1348 | 1349 | ObjectDumper.Write(sortedProducts); 1350 | } 1351 | ``` 1352 | ```clojure 1353 | ;;clojure 1354 | (defn linq33 [] 1355 | (let [products products-list 1356 | sorted-products (reverse (sort-by :units-in-stock products))] 1357 | (doseq [p sorted-products] (println p)))) 1358 | ``` 1359 | #### Output 1360 | 1361 | #clj_linq.data.Product{:product-id 75, :product-name Rhönbräu Klosterbier, :category Beverages, :unit-price 7.75, :units-in-stock 125} 1362 | #clj_linq.data.Product{:product-id 40, :product-name Boston Crab Meat, :category Seafood, :unit-price 18.4, :units-in-stock 123} 1363 | #clj_linq.data.Product{:product-id 6, :product-name Grandma's Boysenberry Spread, :category Condiments, :unit-price 25.0, :units-in-stock 120} 1364 | #clj_linq.data.Product{:product-id 55, :product-name Pâté chinois, :category Meat/Poultry, :unit-price 24.0, :units-in-stock 115} 1365 | #clj_linq.data.Product{:product-id 61, :product-name Sirop d'érable, :category Condiments, :unit-price 28.5, :units-in-stock 113} 1366 | ... 1367 | 1368 | ### linq34: OrderByDescending - Comparer 1369 | ```csharp 1370 | //c# 1371 | public void Linq34() 1372 | { 1373 | string[] words = { "aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr", "cHeRry" }; 1374 | 1375 | var sortedWords = words.OrderByDescending(a => a, new CaseInsensitiveComparer()); 1376 | 1377 | ObjectDumper.Write(sortedWords); 1378 | } 1379 | ``` 1380 | ```clojure 1381 | ;;clojure 1382 | (defn linq34 [] 1383 | (let [words ["aPPLE" "AbAcUs" "bRaNcH" "BlUeBeRrY" "ClOvEr" "cHeRry"] 1384 | sorted-words (->> words 1385 | (sort-by identity case-insensitive-compare) 1386 | reverse)] 1387 | (doseq [w sorted-words] (println w)))) 1388 | ``` 1389 | #### Output 1390 | 1391 | ClOvEr 1392 | cHeRry 1393 | bRaNcH 1394 | BlUeBeRrY 1395 | aPPLE 1396 | AbAcUs 1397 | 1398 | ### linq35: ThenBy - Simple 1399 | ```csharp 1400 | //c# 1401 | public void Linq35() 1402 | { 1403 | string[] digits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; 1404 | 1405 | var sortedDigits = 1406 | from d in digits 1407 | orderby d.Length, d 1408 | select d; 1409 | 1410 | Console.WriteLine("Sorted digits:"); 1411 | foreach (var d in sortedDigits) 1412 | { 1413 | Console.WriteLine(d); 1414 | } 1415 | } 1416 | ``` 1417 | ```clojure 1418 | ;;clojure 1419 | (defn linq35 [] 1420 | (let [digits ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"] 1421 | sorted-digits (order-by [count identity] digits)] 1422 | (println "Sorted digits:") 1423 | (doseq [d sorted-digits] (println d)))) 1424 | ``` 1425 | #### Output 1426 | 1427 | Sorted digits: 1428 | one 1429 | six 1430 | two 1431 | five 1432 | four 1433 | nine 1434 | zero 1435 | eight 1436 | seven 1437 | three 1438 | 1439 | ### linq36: ThenBy - Comparer 1440 | ```csharp 1441 | //c# 1442 | public void Linq36() 1443 | { 1444 | string[] words = { "aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr", "cHeRry" }; 1445 | 1446 | var sortedWords = 1447 | words.OrderBy(a => a.Length) 1448 | .ThenBy(a => a, new CaseInsensitiveComparer()); 1449 | 1450 | ObjectDumper.Write(sortedWords); 1451 | } 1452 | ``` 1453 | ```clojure 1454 | ;;clojure 1455 | (defn linq36 [] 1456 | (let [words ["aPPLE" "AbAcUs" "bRaNcH" "BlUeBeRrY" "ClOvEr" "cHeRry"] 1457 | sorted-words (order-by [count (fn [x] (.toLowerCase x))] words)] 1458 | (doseq [w sorted-words] (println w)))) 1459 | ``` 1460 | #### Output 1461 | 1462 | aPPLE 1463 | AbAcUs 1464 | bRaNcH 1465 | cHeRry 1466 | ClOvEr 1467 | BlUeBeRrY 1468 | 1469 | ### linq37: ThenByDescending - Simple 1470 | ```csharp 1471 | //c# 1472 | public void Linq37() 1473 | { 1474 | List products = GetProductList(); 1475 | 1476 | var sortedProducts = 1477 | from p in products 1478 | orderby p.Category, p.UnitPrice descending 1479 | select p; 1480 | 1481 | ObjectDumper.Write(sortedProducts); 1482 | } 1483 | ``` 1484 | ```clojure 1485 | ;;clojure 1486 | (defn linq37 [] 1487 | (let [products products-list 1488 | sorted-products (order-by [:category #(* -1 (:unit-price %))] products)] 1489 | (doseq [p sorted-products] (println p)))) 1490 | ``` 1491 | #### Output 1492 | 1493 | #clj_linq.data.Product{:product-id 38, :product-name Côte de Blaye, :category Beverages, :unit-price 263.5, :units-in-stock 17} 1494 | #clj_linq.data.Product{:product-id 43, :product-name Ipoh Coffee, :category Beverages, :unit-price 46.0, :units-in-stock 17} 1495 | #clj_linq.data.Product{:product-id 2, :product-name Chang, :category Beverages, :unit-price 19.0, :units-in-stock 17} 1496 | #clj_linq.data.Product{:product-id 1, :product-name Chai, :category Beverages, :unit-price 18.0, :units-in-stock 39} 1497 | #clj_linq.data.Product{:product-id 35, :product-name Steeleye Stout, :category Beverages, :unit-price 18.0, :units-in-stock 20} 1498 | #clj_linq.data.Product{:product-id 39, :product-name Chartreuse verte, :category Beverages, :unit-price 18.0, :units-in-stock 69} 1499 | #clj_linq.data.Product{:product-id 76, :product-name Lakkalikööri, :category Beverages, :unit-price 18.0, :units-in-stock 57} 1500 | #clj_linq.data.Product{:product-id 70, :product-name Outback Lager, :category Beverages, :unit-price 15.0, :units-in-stock 15} 1501 | #clj_linq.data.Product{:product-id 34, :product-name Sasquatch Ale, :category Beverages, :unit-price 14.0, :units-in-stock 111} 1502 | ... 1503 | 1504 | ### linq38: ThenByDescending - Comparer 1505 | ```csharp 1506 | //c# 1507 | public void Linq38() 1508 | { 1509 | string[] words = { "aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr", "cHeRry" }; 1510 | 1511 | var sortedWords = 1512 | words.OrderBy(a => a.Length) 1513 | .ThenByDescending(a => a, new CaseInsensitiveComparer()); 1514 | 1515 | ObjectDumper.Write(sortedWords); 1516 | } 1517 | ``` 1518 | ```clojure 1519 | ;;clojure 1520 | (defn linq38 [] 1521 | (let [words ["aPPLE" "AbAcUs" "bRaNcH" "BlUeBeRrY" "ClOvEr" "cHeRry"] 1522 | sorted-words (order-by-comparers 1523 | [#(compare (count %1) (count %2)) 1524 | #(case-insensitive-compare %2 %1)] 1525 | words)] 1526 | (doseq [w sorted-words] (println w)))) 1527 | ``` 1528 | #### Output 1529 | 1530 | aPPLE 1531 | ClOvEr 1532 | cHeRry 1533 | bRaNcH 1534 | AbAcUs 1535 | BlUeBeRrY 1536 | 1537 | ### linq39: Reverse 1538 | ```csharp 1539 | //c# 1540 | public void Linq39() 1541 | { 1542 | string[] digits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; 1543 | 1544 | var reversedIDigits = ( 1545 | from d in digits 1546 | where d[1] == 'i' 1547 | select d) 1548 | .Reverse(); 1549 | 1550 | Console.WriteLine("A backwards list of the digits with a second character of 'i':"); 1551 | foreach (var d in reversedIDigits) 1552 | { 1553 | Console.WriteLine(d); 1554 | } 1555 | } 1556 | ``` 1557 | ```clojure 1558 | ;;clojure 1559 | (defn linq39 [] 1560 | (let [digits ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"] 1561 | sorted-digits (->> digits 1562 | (filter #(= (get % 1) \i)) 1563 | reverse)] 1564 | (println "A backwards list of the digits with a second character of 'i':") 1565 | (doseq [d sorted-digits] (println d)))) 1566 | ``` 1567 | #### Output 1568 | 1569 | A backwards list of the digits with a second character of 'i': 1570 | nine 1571 | eight 1572 | six 1573 | five 1574 | 1575 | LINQ - Grouping Operators 1576 | ------------------------- 1577 | 1578 | ### C# utils added 1579 | 1580 | ```csharp 1581 | public class AnagramEqualityComparer : IEqualityComparer 1582 | { 1583 | public bool Equals(string x, string y) 1584 | { 1585 | return getCanonicalString(x) == getCanonicalString(y); 1586 | } 1587 | 1588 | public int GetHashCode(string obj) 1589 | { 1590 | return getCanonicalString(obj).GetHashCode(); 1591 | } 1592 | 1593 | private string getCanonicalString(string word) 1594 | { 1595 | char[] wordChars = word.ToCharArray(); 1596 | Array.Sort(wordChars); 1597 | return new string(wordChars); 1598 | } 1599 | } 1600 | ``` 1601 | 1602 | ### Clojure utils added 1603 | 1604 | ```clojure 1605 | (defn anagram-comparer [a b] (compare (sort (.toCharArray a)) (sort (.toCharArray b)))) 1606 | ``` 1607 | 1608 | ### linq40: GroupBy - Simple 1 1609 | ```csharp 1610 | //c# 1611 | public void Linq40() 1612 | { 1613 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 1614 | 1615 | var numberGroups = 1616 | from n in numbers 1617 | group n by n % 5 into g 1618 | select new { Remainder = g.Key, Numbers = g }; 1619 | 1620 | foreach (var g in numberGroups) 1621 | { 1622 | Console.WriteLine("Numbers with a remainder of {0} when divided by 5:", g.Remainder); 1623 | foreach (var n in g.Numbers) 1624 | { 1625 | Console.WriteLine(n); 1626 | } 1627 | } 1628 | } 1629 | ``` 1630 | ```clojure 1631 | ;;clojure 1632 | (defn linq40 [] 1633 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 1634 | number-groups (for [g (group-by #(mod % 5) numbers)] 1635 | {:remainder (first g), :numbers (second g)})] 1636 | (doseq [g number-groups] 1637 | (println "Numbers with a remainder of" (:remainder g) "when divided by 5:") 1638 | (doall (map println (:numbers g)))))) 1639 | ``` 1640 | #### Output 1641 | 1642 | Numbers with a remainder of 0 when divided by 5: 1643 | 5 1644 | 0 1645 | Numbers with a remainder of 4 when divided by 5: 1646 | 4 1647 | 9 1648 | Numbers with a remainder of 1 when divided by 5: 1649 | 1 1650 | 6 1651 | Numbers with a remainder of 3 when divided by 5: 1652 | 3 1653 | 8 1654 | Numbers with a remainder of 2 when divided by 5: 1655 | 7 1656 | 2 1657 | 1658 | ### linq41: GroupBy - Simple 2 1659 | ```csharp 1660 | //c# 1661 | public void Linq41() 1662 | { 1663 | string[] words = { "blueberry", "chimpanzee", "abacus", "banana", "apple", "cheese" }; 1664 | 1665 | var wordGroups = 1666 | from w in words 1667 | group w by w[0] into g 1668 | select new { FirstLetter = g.Key, Words = g }; 1669 | 1670 | foreach (var g in wordGroups) 1671 | { 1672 | Console.WriteLine("Words that start with the letter '{0}':", g.FirstLetter); 1673 | foreach (var w in g.Words) 1674 | { 1675 | Console.WriteLine(w); 1676 | } 1677 | } 1678 | } 1679 | ``` 1680 | ```clojure 1681 | ;;clojure 1682 | (defn linq41 [] 1683 | (let [words ["blueberry" "chimpanzee" "abacus" "banana" "apple" "cheese"] 1684 | word-groups (for [g (group-by #(first %) words)] 1685 | {:first-letter (first g), :words (second g)})] 1686 | (doseq [g word-groups] 1687 | (println "Words that start with the letter: " (:first-letter g)) 1688 | (doall (map println (:words g)))))) 1689 | ``` 1690 | 1691 | #### Output 1692 | 1693 | Words that start with the letter: b 1694 | blueberry 1695 | banana 1696 | Words that start with the letter: c 1697 | chimpanzee 1698 | cheese 1699 | Words that start with the letter: a 1700 | abacus 1701 | apple 1702 | 1703 | ### linq42: GroupBy - Simple 3 1704 | ```csharp 1705 | //c# 1706 | public void Linq42() 1707 | { 1708 | List products = GetProductList(); 1709 | 1710 | var orderGroups = 1711 | from p in products 1712 | group p by p.Category into g 1713 | select new { Category = g.Key, Products = g }; 1714 | 1715 | ObjectDumper.Write(orderGroups, 1); 1716 | } 1717 | ``` 1718 | ```clojure 1719 | ;;clojure 1720 | (defn linq42 [] 1721 | (let [products products-list 1722 | order-groups (for [g (group-by #(:category %) products)] 1723 | {:category (first g), :products (second g)})] 1724 | (doseq [x order-groups] (println x)))) 1725 | ``` 1726 | #### Output 1727 | 1728 | {:products [#clj_linq.data.Product{:product-id 1, :product-name Chai, :category Beverages, :unit-price 18.0, :units-in-stock 39} #clj_linq.data.Product{:product-id 2, :product-name Chang, :category Beverages, :unit-price 19.0, :units-in-stock 17} #clj_linq.data.Product{:product-id 24, :product-name Guaraná Fantástica, :category Beverages, :unit-price 4.5, :units-in-stock 20} #clj_linq.data.Product{:product-id 34, :product-name Sasquatch Ale, :category Beverages, :unit-price 14.0, :units-in-stock 111} #clj_linq.data.Product{:product-id 35, :product-name Steeleye Stout, :category Beverages, :unit-price 18.0, :units-in-stock 20} #clj_linq.data.Product{:product-id 38, :product-name Côte de Blaye, :category Beverages, :unit-price 263.5, :units-in-stock 17} #clj_linq.data.Product{:product-id 39, :product-name Chartreuse verte, :category Beverages, :unit-price 18.0, :units-in-stock 69} #clj_linq.data.Product{:product-id 43, :product-name Ipoh Coffee, :category Beverages, :unit-price 46.0, :units-in-stock 17} #clj_linq.data.Product{:product-id 67, :product-name Laughing Lumberjack Lager, :category Beverages, :unit-price 14.0, :units-in-stock 52} #clj_linq.data.Product{:product-id 70, :product-name Outback Lager, :category Beverages, :unit-price 15.0, :units-in-stock 15} #clj_linq.data.Product{:product-id 75, :product-name Rhönbräu Klosterbier, :category Beverages, :unit-price 7.75, :units-in-stock 125} #clj_linq.data.Product{:product-id 76, :product-name Lakkalikööri, :category Beverages, :unit-price 18.0, :units-in-stock 57}], :category Beverages} 1729 | {:products [#clj_linq.data.Product{:product-id 3, :product-name Aniseed Syrup, :category Condiments, :unit-price 10.0, :units-in-stock 13} #clj_linq.data.Product{:product-id 4, :product-name Chef Anton's Cajun Seasoning, :category Condiments, :unit-price 22.0, :units-in-stock 53} #clj_linq.data.Product{:product-id 5, :product-name Chef Anton's Gumbo Mix, :category Condiments, :unit-price 21.35, :units-in-stock 0} #clj_linq.data.Product{:product-id 6, :product-name Grandma's Boysenberry Spread, :category Condiments, :unit-price 25.0, :units-in-stock 120} #clj_linq.data.Product{:product-id 8, :product-name Northwoods Cranberry Sauce, :category Condiments, :unit-price 40.0, :units-in-stock 6} #clj_linq.data.Product{:product-id 15, :product-name Genen Shouyu, :category Condiments, :unit-price 15.5, :units-in-stock 39} #clj_linq.data.Product{:product-id 44, :product-name Gula Malacca, :category Condiments, :unit-price 19.45, :units-in-stock 27} #clj_linq.data.Product{:product-id 61, :product-name Sirop d'érable, :category Condiments, :unit-price 28.5, :units-in-stock 113} #clj_linq.data.Product{:product-id 63, :product-name Vegie-spread, :category Condiments, :unit-price 43.9, :units-in-stock 24} #clj_linq.data.Product{:product-id 65, :product-name Louisiana Fiery Hot Pepper Sauce, :category Condiments, :unit-price 21.05, :units-in-stock 76} #clj_linq.data.Product{:product-id 66, :product-name Louisiana Hot Spiced Okra, :category Condiments, :unit-price 17.0, :units-in-stock 4} #clj_linq.data.Product{:product-id 77, :product-name Original Frankfurter grüne Soße, :category Condiments, :unit-price 13.0, :units-in-stock 32}], :category Condiments} 1730 | 1731 | ### linq43: GroupBy - Nested 1732 | ```csharp 1733 | //c# 1734 | public void Linq43() 1735 | { 1736 | List customers = GetCustomerList(); 1737 | 1738 | var customerOrderGroups = 1739 | from c in customers 1740 | select 1741 | new 1742 | { 1743 | c.CompanyName, 1744 | YearGroups = 1745 | from o in c.Orders 1746 | group o by o.OrderDate.Year into yg 1747 | select 1748 | new 1749 | { 1750 | Year = yg.Key, 1751 | MonthGroups = 1752 | from o in yg 1753 | group o by o.OrderDate.Month into mg 1754 | select new { Month = mg.Key, Orders = mg } 1755 | } 1756 | }; 1757 | 1758 | ObjectDumper.Write(customerOrderGroups, 3); 1759 | } 1760 | ``` 1761 | ```clojure 1762 | ;;clojure 1763 | (defn linq43 [] 1764 | (let [customers customers-list 1765 | customer-order-groups 1766 | (for [c customers] 1767 | {:company-name (:company-name c), 1768 | :year-groups 1769 | (for [yg (group-by #(time/year (:order-date %)) (:orders c))] 1770 | {:year (first yg) 1771 | :month-groups 1772 | (for [mg (group-by #(:order-date %) (second yg))] 1773 | {:month (time/month (first mg)), :orders (second mg)})})})] 1774 | (doseq [x customer-order-groups] (println x)))) 1775 | ``` 1776 | #### Output 1777 | 1778 | {:company-name Alfreds Futterkiste, :year-groups ({:month-groups ({:month 8, :orders [#clj_linq.data.Order{:order-id 10643, :order-date #, :total 814.50M}]} {:month 10, :orders [#clj_linq.data.Order{:order-id 10692, :order-date #, :total 878.00M}]} {:month 10, :orders [#clj_linq.data.Order{:order-id 10702, :order-date #, :total 330.00M}]} {:month 1, :orders [#clj_linq.data.Order{:order-id 10835, :order-date #, :total 845.80M}]} {:month 3, :orders [#clj_linq.data.Order{:order-id 10952, :order-date #, :total 471.20M}]} {:month 4, :orders [#clj_linq.data.Order{:order-id 11011, :order-date #, :total 933.50M}]}), :year nil})} 1779 | 1780 | ### linq44: GroupBy - Comparer 1781 | ```csharp 1782 | //c# 1783 | public void Linq44() 1784 | { 1785 | string[] anagrams = { "from ", " salt", " earn ", " last ", " near ", " form " }; 1786 | 1787 | var orderGroups = anagrams.GroupBy(w => w.Trim(), new AnagramEqualityComparer()); 1788 | 1789 | ObjectDumper.Write(orderGroups, 1); 1790 | } 1791 | ``` 1792 | ```clojure 1793 | ;;clojure 1794 | (defn linq44 [] 1795 | (let [anagrams ["from " " salt" " earn " " last " " near " " form "] 1796 | order-groups (group-by #(sort (.toCharArray (.trim %))) anagrams)] 1797 | (doseq [x order-groups] (println (second x))))) 1798 | ``` 1799 | 1800 | #### Output 1801 | 1802 | [from form ] 1803 | [ salt last ] 1804 | [ earn near ] 1805 | 1806 | ### linq45: GroupBy - Comparer, Mapped 1807 | ```csharp 1808 | //c# 1809 | public void Linq45() 1810 | { 1811 | string[] anagrams = { "from ", " salt", " earn ", " last ", " near ", " form " }; 1812 | 1813 | var orderGroups = anagrams.GroupBy( 1814 | w => w.Trim(), 1815 | a => a.ToUpper(), 1816 | new AnagramEqualityComparer() 1817 | ); 1818 | 1819 | ObjectDumper.Write(orderGroups, 1); 1820 | } 1821 | ``` 1822 | ```clojure 1823 | ;;clojure 1824 | (defn linq45 [] 1825 | (let [anagrams ["from " " salt" " earn " " last " " near " " form "] 1826 | order-groups (group-by #(sort (.toCharArray (.trim %))) 1827 | (map #(.toUpperCase %) anagrams))] 1828 | (doseq [x order-groups] (println (second x))))) 1829 | ``` 1830 | #### Output 1831 | 1832 | [FROM FORM ] 1833 | [ SALT LAST ] 1834 | [ EARN NEAR ] 1835 | 1836 | 1837 | LINQ - Set Operators 1838 | -------------------- 1839 | 1840 | ### linq46: Distinct - 1 1841 | ```csharp 1842 | //c# 1843 | public void Linq46() 1844 | { 1845 | int[] factorsOf300 = { 2, 2, 3, 5, 5 }; 1846 | 1847 | var uniqueFactors = factorsOf300.Distinct(); 1848 | 1849 | Console.WriteLine("Prime factors of 300:"); 1850 | foreach (var f in uniqueFactors) 1851 | { 1852 | Console.WriteLine(f); 1853 | } 1854 | } 1855 | ``` 1856 | ```clojure 1857 | ;;clojure 1858 | (defn linq46 [] 1859 | (let [factors-of-300 [2, 2, 3, 5, 5] 1860 | unique-factors (distinct factors-of-300)] 1861 | (println "Prime factors of 300:") 1862 | (doseq [n unique-factors] (println n)))) 1863 | ``` 1864 | #### Output 1865 | 1866 | Prime factors of 300: 1867 | 2 1868 | 3 1869 | 5 1870 | 1871 | ### linq47: Distinct - 2 1872 | ```csharp 1873 | //c# 1874 | public void Linq47() 1875 | { 1876 | List products = GetProductList(); 1877 | 1878 | var categoryNames = ( 1879 | from p in products 1880 | select p.Category) 1881 | .Distinct(); 1882 | 1883 | Console.WriteLine("Category names:"); 1884 | foreach (var n in categoryNames) 1885 | { 1886 | Console.WriteLine(n); 1887 | } 1888 | } 1889 | ``` 1890 | ```clojure 1891 | ;;clojure 1892 | (defn linq47 [] 1893 | (let [products products-list 1894 | category-names (->> products 1895 | (map :category) 1896 | distinct)] 1897 | (println "Category names:") 1898 | (doseq [c category-names] (println c)))) 1899 | ``` 1900 | #### Output 1901 | 1902 | Category names: 1903 | Beverages 1904 | Condiments 1905 | Produce 1906 | Meat/Poultry 1907 | Seafood 1908 | Dairy Products 1909 | Confections 1910 | Grains/Cereals 1911 | 1912 | ### linq48: Union - 1 1913 | ```csharp 1914 | //c# 1915 | public void Linq48() 1916 | { 1917 | int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 }; 1918 | int[] numbersB = { 1, 3, 5, 7, 8 }; 1919 | 1920 | var uniqueNumbers = numbersA.Union(numbersB); 1921 | 1922 | Console.WriteLine("Unique numbers from both arrays:"); 1923 | foreach (var n in uniqueNumbers) 1924 | { 1925 | Console.WriteLine(n); 1926 | } 1927 | } 1928 | ``` 1929 | ```clojure 1930 | ;;clojure 1931 | (defn linq48 [] 1932 | (let [numbers-a [0 2 4 5 6 8 9] 1933 | numbers-b [1 3 5 7 8] 1934 | unique-numbers (union (set numbers-a) (set numbers-b))] 1935 | (println "Unique numbers from both arrays:") 1936 | (doseq [n unique-numbers] (println n)))) 1937 | ``` 1938 | #### Output 1939 | 1940 | Unique numbers from both arrays: 1941 | 0 1942 | 1 1943 | 2 1944 | 3 1945 | 4 1946 | 5 1947 | 6 1948 | 7 1949 | 8 1950 | 9 1951 | 1952 | ### linq49: Union - 2 1953 | ```csharp 1954 | //c# 1955 | public void Linq49() 1956 | { 1957 | List products = GetProductList(); 1958 | List customers = GetCustomerList(); 1959 | 1960 | var productFirstChars = 1961 | from p in products 1962 | select p.ProductName[0]; 1963 | var customerFirstChars = 1964 | from c in customers 1965 | select c.CompanyName[0]; 1966 | 1967 | var uniqueFirstChars = productFirstChars.Union(customerFirstChars); 1968 | 1969 | Console.WriteLine("Unique first letters from Product names and Customer names:"); 1970 | foreach (var ch in uniqueFirstChars) 1971 | { 1972 | Console.WriteLine(ch); 1973 | } 1974 | } 1975 | ``` 1976 | ```clojure 1977 | ;;clojure 1978 | (defn linq49 [] 1979 | (let [products products-list 1980 | customers customers-list 1981 | product-first-chars (map #(first (:product-name %)) products) 1982 | customer-first-chars (map #(first (:company-name %)) customers) 1983 | unique-first-chars (union (set product-first-chars) (set customer-first-chars))] 1984 | (println "Unique first letters from Product names and Customer names:") 1985 | (doseq [x unique-first-chars] (println x)))) 1986 | ``` 1987 | #### Output 1988 | 1989 | Unique first letters from Product names and Customer names: 1990 | A 1991 | B 1992 | C 1993 | D 1994 | E 1995 | F 1996 | G 1997 | H 1998 | I 1999 | J 2000 | K 2001 | L 2002 | M 2003 | N 2004 | O 2005 | P 2006 | Q 2007 | R 2008 | S 2009 | T 2010 | U 2011 | V 2012 | W 2013 | Z 2014 | 2015 | ### linq50: Intersect - 1 2016 | ```csharp 2017 | //c# 2018 | public void Linq50() 2019 | { 2020 | int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 }; 2021 | int[] numbersB = { 1, 3, 5, 7, 8 }; 2022 | 2023 | var commonNumbers = numbersA.Intersect(numbersB); 2024 | 2025 | Console.WriteLine("Common numbers shared by both arrays:"); 2026 | foreach (var n in commonNumbers) 2027 | { 2028 | Console.WriteLine(n); 2029 | } 2030 | } 2031 | ``` 2032 | ```clojure 2033 | ;;clojure 2034 | (defn linq50 [] 2035 | (let [numbers-a [0 2 4 5 6 8 9] 2036 | numbers-b [1 3 5 7 8] 2037 | common-numbers (intersection (set numbers-a) (set numbers-b))] 2038 | (println "Common numbers shared by both arrays:") 2039 | (doseq [n common-numbers] (println n)))) 2040 | ``` 2041 | #### Output 2042 | 2043 | Common numbers shared by both arrays: 2044 | 5 2045 | 8 2046 | 2047 | ### linq51: Intersect - 2 2048 | ```csharp 2049 | //c# 2050 | public void Linq51() 2051 | { 2052 | List products = GetProductList(); 2053 | List customers = GetCustomerList(); 2054 | 2055 | var productFirstChars = 2056 | from p in products 2057 | select p.ProductName[0]; 2058 | var customerFirstChars = 2059 | from c in customers 2060 | select c.CompanyName[0]; 2061 | 2062 | var commonFirstChars = productFirstChars.Intersect(customerFirstChars); 2063 | 2064 | Console.WriteLine("Common first letters from Product names and Customer names:"); 2065 | foreach (var ch in commonFirstChars) 2066 | { 2067 | Console.WriteLine(ch); 2068 | } 2069 | } 2070 | ``` 2071 | ```clojure 2072 | ;;clojure 2073 | (defn linq51 [] 2074 | (let [products products-list 2075 | customers customers-list 2076 | product-first-chars (map #(first (:product-name %)) products) 2077 | customer-first-chars (map #(first (:company-name %)) customers) 2078 | common-first-chars (intersection (set product-first-chars) (set customer-first-chars))] 2079 | (println "Common first letters from Product names and Customer names:") 2080 | (doseq [x common-first-chars] (println x)))) 2081 | ``` 2082 | #### Output 2083 | 2084 | Common first letters from Product names and Customer names: 2085 | A 2086 | B 2087 | C 2088 | E 2089 | F 2090 | G 2091 | I 2092 | K 2093 | L 2094 | M 2095 | N 2096 | O 2097 | P 2098 | Q 2099 | R 2100 | S 2101 | T 2102 | V 2103 | W 2104 | 2105 | ### linq52: Except - 1 2106 | ```csharp 2107 | //c# 2108 | public void Linq52() 2109 | { 2110 | int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 }; 2111 | int[] numbersB = { 1, 3, 5, 7, 8 }; 2112 | 2113 | IEnumerable aOnlyNumbers = numbersA.Except(numbersB); 2114 | 2115 | Console.WriteLine("Numbers in first array but not second array:"); 2116 | foreach (var n in aOnlyNumbers) 2117 | { 2118 | Console.WriteLine(n); 2119 | } 2120 | } 2121 | ``` 2122 | ```clojure 2123 | ;;clojure 2124 | (defn linq52 [] 2125 | (let [numbers-a [0 2 4 5 6 8 9] 2126 | numbers-b [1 3 5 7 8] 2127 | a-only-numbers (difference (set numbers-a) (set numbers-b))] 2128 | (println "Numbers in first array but not second array:") 2129 | (doseq [n a-only-numbers] (println n)))) 2130 | ``` 2131 | #### Output 2132 | 2133 | Numbers in first array but not second array: 2134 | 0 2135 | 2 2136 | 4 2137 | 6 2138 | 9 2139 | 2140 | ### linq53: Except - 2 2141 | ```csharp 2142 | //c# 2143 | public void Linq53() 2144 | { 2145 | List products = GetProductList(); 2146 | List customers = GetCustomerList(); 2147 | 2148 | var productFirstChars = 2149 | from p in products 2150 | select p.ProductName[0]; 2151 | var customerFirstChars = 2152 | from c in customers 2153 | select c.CompanyName[0]; 2154 | 2155 | var productOnlyFirstChars = productFirstChars.Except(customerFirstChars); 2156 | 2157 | Console.WriteLine("First letters from Product names, but not from Customer names:"); 2158 | foreach (var ch in productOnlyFirstChars) 2159 | { 2160 | Console.WriteLine(ch); 2161 | } 2162 | } 2163 | ``` 2164 | ```clojure 2165 | ;;clojure 2166 | (defn linq53 [] 2167 | (let [products products-list 2168 | customers customers-list 2169 | product-first-chars (map #(first (:product-name %)) products) 2170 | customer-first-chars (map #(first (:company-name %)) customers) 2171 | product-only-first-chars (difference (set product-first-chars) 2172 | (set customer-first-chars))] 2173 | (println "First letters from Product names, but not from Customer names:") 2174 | (doseq [x product-only-first-chars] (println x)))) 2175 | ``` 2176 | #### Output 2177 | 2178 | First letters from Product names, but not from Customer names: 2179 | J 2180 | U 2181 | Z 2182 | 2183 | 2184 | LINQ - Conversion Operators 2185 | --------------------------- 2186 | 2187 | ### linq54: ToArray 2188 | ```csharp 2189 | //c# 2190 | public void Linq54() 2191 | { 2192 | double[] doubles = { 1.7, 2.3, 1.9, 4.1, 2.9 }; 2193 | 2194 | var sortedDoubles = 2195 | from d in doubles 2196 | orderby d descending 2197 | select d; 2198 | var doublesArray = sortedDoubles.ToArray(); 2199 | 2200 | Console.WriteLine("Every other double from highest to lowest:"); 2201 | for (int d = 0; d < doublesArray.Length; d += 2) 2202 | { 2203 | Console.WriteLine(doublesArray[d]); 2204 | } 2205 | } 2206 | ``` 2207 | ```clojure 2208 | ;;clojure 2209 | (defn linq54 [] 2210 | (let [dbls [1.7 2.3 1.9 4.1 2.9] 2211 | sorted-doubles (->> dbls sort reverse)] 2212 | (println "Every other double from highest to lowest:") 2213 | (doseq [d (take-nth 2 sorted-doubles)] (println d)))) 2214 | ``` 2215 | #### Output 2216 | 2217 | Every other double from highest to lowest: 2218 | 4.1 2219 | 2.3 2220 | 1.7 2221 | 2222 | ### linq55: ToList 2223 | ```csharp 2224 | //c# 2225 | public void Linq55() 2226 | { 2227 | string[] words = { "cherry", "apple", "blueberry" }; 2228 | 2229 | var sortedWords = 2230 | from w in words 2231 | orderby w 2232 | select w; 2233 | var wordList = sortedWords.ToList(); 2234 | 2235 | Console.WriteLine("The sorted word list:"); 2236 | foreach (var w in wordList) 2237 | { 2238 | Console.WriteLine(w); 2239 | } 2240 | } 2241 | ``` 2242 | ```clojure 2243 | ;;clojure 2244 | (defn linq55 [] 2245 | (let [words ["cherry", "apple", "blueberry"] 2246 | sorted-words (->> words 2247 | sort 2248 | (apply list))] 2249 | (println "The sorted word list:") 2250 | (doseq [w sorted-words] (println w)))) 2251 | ``` 2252 | #### Output 2253 | 2254 | The sorted word list: 2255 | apple 2256 | blueberry 2257 | cherry 2258 | 2259 | ### linq56: ToDictionary 2260 | ```csharp 2261 | //c# 2262 | public void Linq56() 2263 | { 2264 | var scoreRecords = new[] { new {Name = "Alice", Score = 50}, 2265 | new {Name = "Bob" , Score = 40}, 2266 | new {Name = "Cathy", Score = 45} 2267 | }; 2268 | 2269 | var scoreRecordsDict = scoreRecords.ToDictionary(sr => sr.Name); 2270 | 2271 | Console.WriteLine("Bob's score: {0}", scoreRecordsDict["Bob"]); 2272 | } 2273 | ``` 2274 | ```clojure 2275 | ;;clojure 2276 | (defn linq56 [] 2277 | (let [sorted-records [{:name "Alice", :score 50} 2278 | {:name "Bob", :score 40} 2279 | {:name "Cathy", :score 45}] 2280 | sorted-records-dict (->> sorted-records 2281 | (map #(hash-map (:name %) (:score %))) 2282 | (into {}))] 2283 | (println "Bob's score:" (sorted-records-dict "Bob")))) 2284 | ``` 2285 | #### Output 2286 | 2287 | Bob's score: 40 2288 | 2289 | ### linq57: OfType 2290 | ```csharp 2291 | //c# 2292 | public void Linq57() 2293 | { 2294 | object[] numbers = { null, 1.0, "two", 3, "four", 5, "six", 7.0 }; 2295 | 2296 | var doubles = numbers.OfType(); 2297 | 2298 | Console.WriteLine("Numbers stored as doubles:"); 2299 | foreach (var d in doubles) 2300 | { 2301 | Console.WriteLine(d); 2302 | } 2303 | } 2304 | ``` 2305 | ```clojure 2306 | ;;clojure 2307 | (defn linq57 [] 2308 | (let [numbers [nil 1.0 "two" 3 "four" 5 "six" 7.0] 2309 | dbls (filter #(= (type %) java.lang.Double) numbers)] 2310 | (println "Numbers stored as doubles:") 2311 | (doseq [d dbls] (println d)))) 2312 | ``` 2313 | #### Output 2314 | 2315 | Numbers stored as doubles: 2316 | 1.0 2317 | 7.0 2318 | 2319 | 2320 | LINQ - Element Operators 2321 | ------------------------ 2322 | 2323 | ### linq58: First - Simple 2324 | ```csharp 2325 | //c# 2326 | public void Linq58() 2327 | { 2328 | List products = GetProductList(); 2329 | 2330 | Product product12 = ( 2331 | from p in products 2332 | where p.ProductID == 12 2333 | select p) 2334 | .First(); 2335 | 2336 | ObjectDumper.Write(product12); 2337 | } 2338 | ``` 2339 | ```clojure 2340 | ;;clojure 2341 | (defn linq58 [] 2342 | (let [products products-list 2343 | product-12 (->> products 2344 | (filter #(= (:product-id %) 12)) 2345 | first)] 2346 | (println product-12))) 2347 | ``` 2348 | #### Output 2349 | 2350 | #clj_linq.data.Product{:product-id 12, :product-name Queso Manchego La Pastora, :category Dairy Products, :unit-price 38.0, :units-in-stock 86} 2351 | 2352 | ### linq59: First - Condition 2353 | ```csharp 2354 | //c# 2355 | public void Linq59() 2356 | { 2357 | string[] strings = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; 2358 | 2359 | string startsWithO = strings.First(s => s[0] == 'o'); 2360 | 2361 | Console.WriteLine("A string starting with 'o': {0}", startsWithO); 2362 | } 2363 | ``` 2364 | ```clojure 2365 | ;;clojure 2366 | (defn linq59 [] 2367 | (let [strings ["zero", "one", "two", "three", "four", 2368 | "five", "six", "seven", "eight", "nine"] 2369 | starts-with-o (first (filter #(= (first %) \o) strings))] 2370 | (println "A string starting with 'o':" starts-with-o))) 2371 | ``` 2372 | #### Output 2373 | 2374 | A string starting with 'o': one 2375 | 2376 | ### linq61: FirstOrDefault - Simple 2377 | ```csharp 2378 | //c# 2379 | public void Linq61() 2380 | { 2381 | int[] numbers = { }; 2382 | 2383 | int firstNumOrDefault = numbers.FirstOrDefault(); 2384 | 2385 | Console.WriteLine(firstNumOrDefault); 2386 | } 2387 | ``` 2388 | ```clojure 2389 | ;;clojure 2390 | (defn linq61 [] 2391 | (let [numbers [] 2392 | first-num-or-default (get numbers 0 0)] 2393 | (println first-num-or-default))) 2394 | ``` 2395 | #### Output 2396 | 2397 | 0 2398 | 2399 | ### linq62: FirstOrDefault - Condition 2400 | ```csharp 2401 | //c# 2402 | public void Linq62() 2403 | { 2404 | List products = GetProductList(); 2405 | 2406 | Product product789 = products.FirstOrDefault(p => p.ProductID == 789); 2407 | 2408 | Console.WriteLine("Product 789 exists: {0}", product789 != null); 2409 | } 2410 | ``` 2411 | ```clojure 2412 | ;;clojure 2413 | (defn linq62 [] 2414 | (let [products products-list 2415 | product-789 (->> products 2416 | (filter #(= (:product-id %) 789)) 2417 | first)] 2418 | (println "Product 789 exists:" (not= product-789 nil)))) 2419 | ``` 2420 | #### Output 2421 | 2422 | Product 789 exists: false 2423 | 2424 | ### linq64: ElementAt 2425 | ```csharp 2426 | //c# 2427 | public void Linq64() 2428 | { 2429 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 2430 | 2431 | int fourthLowNum = ( 2432 | from n in numbers 2433 | where n > 5 2434 | select n) 2435 | .ElementAt(1); // second number is index 1 because sequences use 0-based indexing 2436 | 2437 | Console.WriteLine("Second number > 5: {0}", fourthLowNum); 2438 | } 2439 | ``` 2440 | ```clojure 2441 | ;;clojure 2442 | (defn linq64 [] 2443 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 2444 | fourth-low-num (->> numbers 2445 | (filter #(> % 5)) 2446 | second)] 2447 | (println "Second number > 5:" fourth-low-num))) 2448 | ``` 2449 | #### Output 2450 | 2451 | Second number > 5: 8 2452 | 2453 | 2454 | LINQ - Generation Operators 2455 | --------------------------- 2456 | 2457 | ### linq65: Range 2458 | ```csharp 2459 | //c# 2460 | public void Linq65() 2461 | { 2462 | var numbers = 2463 | from n in Enumerable.Range(100, 50) 2464 | 2465 | select new { Number = n, OddEven = n % 2 == 1 ? "odd" : "even" }; 2466 | 2467 | foreach (var n in numbers) 2468 | { 2469 | Console.WriteLine("The number {0} is {1}.", n.Number, n.OddEven); 2470 | } 2471 | } 2472 | ``` 2473 | ```clojure 2474 | ;;clojure 2475 | (defn linq65 [] 2476 | (let [numbers (for [n (range 100 151)] 2477 | {:number n, 2478 | :odd-even (if (= (mod n 2) 1) "odd" "even")})] 2479 | (doseq [n numbers] (println "The number" (:number n) "is" (:odd-even n))))) 2480 | ``` 2481 | #### Output 2482 | 2483 | The number 100 is even 2484 | The number 101 is odd 2485 | The number 102 is even 2486 | The number 103 is odd 2487 | The number 104 is even 2488 | The number 105 is odd 2489 | The number 106 is even 2490 | The number 107 is odd 2491 | The number 108 is even 2492 | The number 109 is odd 2493 | The number 110 is even 2494 | ... 2495 | 2496 | ### linq66: Repeat 2497 | ```csharp 2498 | //c# 2499 | public void Linq66() 2500 | { 2501 | var numbers = Enumerable.Repeat(7, 10); 2502 | 2503 | foreach (var n in numbers) 2504 | { 2505 | Console.WriteLine(n); 2506 | } 2507 | } 2508 | ``` 2509 | ```clojure 2510 | ;;clojure 2511 | (defn linq66 [] 2512 | (let [numbers (repeat 10 7)] 2513 | (doseq [n numbers] (println n)))) 2514 | ``` 2515 | #### Output 2516 | 2517 | 7 2518 | 7 2519 | 7 2520 | 7 2521 | 7 2522 | 7 2523 | 7 2524 | 7 2525 | 7 2526 | 7 2527 | 2528 | 2529 | LINQ - Quantifiers 2530 | ------------------ 2531 | 2532 | ### linq67: Any - Simple 2533 | ```csharp 2534 | //c# 2535 | public void Linq67() 2536 | { 2537 | string[] words = { "believe", "relief", "receipt", "field" }; 2538 | 2539 | bool iAfterE = words.Any(w => w.Contains("ei")); 2540 | 2541 | Console.WriteLine("There is a word that contains in the list that contains 'ei': {0}", iAfterE); 2542 | } 2543 | ``` 2544 | ```clojure 2545 | ;;clojure 2546 | (defn linq67 [] 2547 | (let [words ["believe" "relief" "receipt" "field"] 2548 | i-after-e (some #(.contains % "ie") words)] 2549 | (println "There is a word that contains in the list that contains 'ei':" i-after-e))) 2550 | ``` 2551 | #### Output 2552 | 2553 | There is a word that contains in the list that contains 'ei': true 2554 | 2555 | ### linq69: Any - Grouped 2556 | ```csharp 2557 | //c# 2558 | public void Linq69() 2559 | { 2560 | List products = GetProductList(); 2561 | var productGroups = 2562 | from p in products 2563 | group p by p.Category into g 2564 | where g.Any(p => p.UnitsInStock == 0) 2565 | select new { Category = g.Key, Products = g }; 2566 | 2567 | ObjectDumper.Write(productGroups, 1); 2568 | } 2569 | ``` 2570 | ```clojure 2571 | ;;clojure 2572 | (defn linq69 [] 2573 | (let [products products-list 2574 | product-groups 2575 | (->> products 2576 | (group-by :category) 2577 | (filter #(some (fn [p] (= (:units-in-stock p) 0)) (get % 1))) 2578 | (map #(identity {:category (first %), :products (second %)})))] 2579 | (doseq [x product-groups] (println x)))) 2580 | ``` 2581 | #### Output 2582 | 2583 | {:category Condiments, :products [#clj_linq.data.Product{:product-id 3, :product-name Aniseed Syrup, :category Condiments, :unit-price 10.0, :units-in-stock 13} #clj_linq.data.Product{:product-id 4, :product-name Chef Anton's Cajun Seasoning, :category Condiments, :unit-price 22.0, :units-in-stock 53} #clj_linq.data.Product{:product-id 5, :product-name Chef Anton's Gumbo Mix, :category Condiments, :unit-price 21.35, :units-in-stock 0} #clj_linq.data.Product{:product-id 6, :product-name Grandma's Boysenberry Spread, :category Condiments, :unit-price 25.0, :units-in-stock 120} #clj_linq.data.Product{:product-id 8, :product-name Northwoods Cranberry Sauce, :category Condiments, :unit-price 40.0, :units-in-stock 6} #clj_linq.data.Product{:product-id 15, :product-name Genen Shouyu, :category Condiments, :unit-price 15.5, :units-in-stock 39} #clj_linq.data.Product{:product-id 44, :product-name Gula Malacca, :category Condiments, :unit-price 19.45, :units-in-stock 27} #clj_linq.data.Product{:product-id 61, :product-name Sirop d'érable, :category Condiments, :unit-price 28.5, :units-in-stock 113} #clj_linq.data.Product{:product-id 63, :product-name Vegie-spread, :category Condiments, :unit-price 43.9, :units-in-stock 24} #clj_linq.data.Product{:product-id 65, :product-name Louisiana Fiery Hot Pepper Sauce, :category Condiments, :unit-price 21.05, :units-in-stock 76} #clj_linq.data.Product{:product-id 66, :product-name Louisiana Hot Spiced Okra, :category Condiments, :unit-price 17.0, :units-in-stock 4} #clj_linq.data.Product{:product-id 77, :product-name Original Frankfurter grüne Soße, :category Condiments, :unit-price 13.0, :units-in-stock 32}]} 2584 | ... 2585 | 2586 | ### linq70: All - Simple 2587 | ```csharp 2588 | //c# 2589 | public void Linq70() 2590 | { 2591 | int[] numbers = { 1, 11, 3, 19, 41, 65, 19 }; 2592 | 2593 | bool onlyOdd = numbers.All(n => n % 2 == 1); 2594 | 2595 | Console.WriteLine("The list contains only odd numbers: {0}", onlyOdd); 2596 | } 2597 | ``` 2598 | ```clojure 2599 | ;;clojure 2600 | (defn linq70 [] 2601 | (let [numbers [1 11 3 19 41 65 19] 2602 | only-odd (every? #(= (mod % 2) 1) numbers)] 2603 | (println "The list contains only odd numbers:" only-odd))) 2604 | ``` 2605 | #### Output 2606 | 2607 | The list contains only odd numbers: true 2608 | 2609 | ### linq72: All - Grouped 2610 | ```csharp 2611 | //c# 2612 | public void Linq72() 2613 | { 2614 | List products = GetProductList(); 2615 | 2616 | var productGroups = 2617 | from p in products 2618 | group p by p.Category into g 2619 | where g.All(p => p.UnitsInStock > 0) 2620 | select new { Category = g.Key, Products = g }; 2621 | 2622 | ObjectDumper.Write(productGroups, 1); 2623 | } 2624 | ``` 2625 | ```clojure 2626 | ;;clojure 2627 | (defn linq72 [] 2628 | (let [products products-list 2629 | product-groups 2630 | (->> products 2631 | (group-by :category) 2632 | (filter #(every? (fn [p] (> (:units-in-stock p) 0)) (second %))) 2633 | (map #(identity {:category (first %), :products (second %)})))] 2634 | (doseq [x product-groups] (println x)))) 2635 | ``` 2636 | #### Output 2637 | 2638 | {:category Beverages, :products [#clj_linq.data.Product{:product-id 1, :product-name Chai, :category Beverages, :unit-price 18.0, :units-in-stock 39} #clj_linq.data.Product{:product-id 2, :product-name Chang, :category Beverages, :unit-price 19.0, :units-in-stock 17} #clj_linq.data.Product{:product-id 24, :product-name Guaraná Fantástica, :category Beverages, :unit-price 4.5, :units-in-stock 20} #clj_linq.data.Product{:product-id 34, :product-name Sasquatch Ale, :category Beverages, :unit-price 14.0, :units-in-stock 111} #clj_linq.data.Product{:product-id 35, :product-name Steeleye Stout, :category Beverages, :unit-price 18.0, :units-in-stock 20} #clj_linq.data.Product{:product-id 38, :product-name Côte de Blaye, :category Beverages, :unit-price 263.5, :units-in-stock 17} #clj_linq.data.Product{:product-id 39, :product-name Chartreuse verte, :category Beverages, :unit-price 18.0, :units-in-stock 69} #clj_linq.data.Product{:product-id 43, :product-name Ipoh Coffee, :category Beverages, :unit-price 46.0, :units-in-stock 17} #clj_linq.data.Product{:product-id 67, :product-name Laughing Lumberjack Lager, :category Beverages, :unit-price 14.0, :units-in-stock 52} #clj_linq.data.Product{:product-id 70, :product-name Outback Lager, :category Beverages, :unit-price 15.0, :units-in-stock 15} #clj_linq.data.Product{:product-id 75, :product-name Rhönbräu Klosterbier, :category Beverages, :unit-price 7.75, :units-in-stock 125} #clj_linq.data.Product{:product-id 76, :product-name Lakkalikööri, :category Beverages, :unit-price 18.0, :units-in-stock 57}]} 2639 | ... 2640 | 2641 | 2642 | LINQ - Aggregate Operators 2643 | -------------------------- 2644 | 2645 | ### Clojure utils added 2646 | ```clojure 2647 | (defn average [coll] (/ (reduce + coll) (count coll))) 2648 | ``` 2649 | 2650 | ### linq73: Count - Simple 2651 | ```csharp 2652 | //c# 2653 | public void Linq73() 2654 | { 2655 | int[] factorsOf300 = { 2, 2, 3, 5, 5 }; 2656 | 2657 | int uniqueFactors = factorsOf300.Distinct().Count(); 2658 | 2659 | Console.WriteLine("There are {0} unique factors of 300.", uniqueFactors); 2660 | } 2661 | ``` 2662 | ```clojure 2663 | ;;clojure 2664 | (defn linq73 [] 2665 | (let [factors-of-300 [2 2 3 5 5] 2666 | unique-factors (count (distinct factors-of-300))] 2667 | (println "There are" unique-factors "unique factors of 300."))) 2668 | ``` 2669 | #### Output 2670 | 2671 | There are 3 unique factors of 300. 2672 | 2673 | ### linq74: Count - Conditional 2674 | ```csharp 2675 | //c# 2676 | public void Linq74() 2677 | { 2678 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 2679 | 2680 | int oddNumbers = numbers.Count(n => n % 2 == 1); 2681 | 2682 | Console.WriteLine("There are {0} odd numbers in the list.", oddNumbers); 2683 | } 2684 | ``` 2685 | ```clojure 2686 | ;;clojure 2687 | (defn linq74 [] 2688 | (let [numbers [4 5 1 3 9 0 6 7 2 0] 2689 | odd-numbers (count (for [n numbers :when (= 1 (mod n 2))] n))] 2690 | (println "There are" odd-numbers "odd numbers in the list."))) 2691 | ``` 2692 | #### Output 2693 | 2694 | There are 5 odd numbers in the list. 2695 | 2696 | ### linq76: Count - Nested 2697 | ```csharp 2698 | //c# 2699 | public void Linq76() 2700 | { 2701 | List customers = GetCustomerList(); 2702 | 2703 | var orderCounts = 2704 | from c in customers 2705 | select new { c.CustomerID, OrderCount = c.Orders.Count() }; 2706 | 2707 | ObjectDumper.Write(orderCounts); 2708 | } 2709 | ``` 2710 | ```clojure 2711 | ;;clojure 2712 | (defn linq76 [] 2713 | (let [customers customers-list 2714 | order-counts 2715 | (for [c customers] 2716 | {:customer-id (:customer-id c) :order-count (count (:orders c))})] 2717 | (doseq [x order-counts] (println x)))) 2718 | ``` 2719 | #### Output 2720 | 2721 | {:customer-id ALFKI, :order-count 6} 2722 | {:customer-id ANATR, :order-count 4} 2723 | {:customer-id ANTON, :order-count 7} 2724 | {:customer-id AROUT, :order-count 13} 2725 | {:customer-id BERGS, :order-count 18} 2726 | {:customer-id BLAUS, :order-count 7} 2727 | {:customer-id BLONP, :order-count 11} 2728 | ... 2729 | 2730 | ### linq77: Count - Grouped 2731 | ```csharp 2732 | //c# 2733 | public void Linq77() 2734 | { 2735 | List products = GetProductList(); 2736 | 2737 | var categoryCounts = 2738 | from p in products 2739 | group p by p.Category into g 2740 | select new { Category = g.Key, ProductCount = g.Count() }; 2741 | 2742 | ObjectDumper.Write(categoryCounts 2743 | } 2744 | ``` 2745 | ```clojure 2746 | ;;clojure 2747 | (defn linq77 [] 2748 | (let [products products-list 2749 | category-counts 2750 | (->> products 2751 | (group-by :category) 2752 | (map #(identity {:category (first %), 2753 | :product-count (count (second %))})))] 2754 | (doseq [x category-counts] (println x)))) 2755 | ``` 2756 | #### Output 2757 | 2758 | {:category Beverages, :product-count 12} 2759 | {:category Condiments, :product-count 12} 2760 | {:category Produce, :product-count 5} 2761 | {:category Meat/Poultry, :product-count 6} 2762 | {:category Seafood, :product-count 12} 2763 | {:category Dairy Products, :product-count 10} 2764 | {:category Confections, :product-count 13} 2765 | {:category Grains/Cereals, :product-count 7} 2766 | 2767 | ### linq78: Sum - Simple 2768 | ```csharp 2769 | //c# 2770 | public void Linq78() 2771 | { 2772 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 2773 | 2774 | double numSum = numbers.Sum(); 2775 | 2776 | Console.WriteLine("The sum of the numbers is {0}.", numSum); 2777 | } 2778 | ``` 2779 | ```clojure 2780 | ;;clojure 2781 | (defn linq78 [] 2782 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 2783 | num-sum (reduce + numbers)] 2784 | (println "The sum of the numbers is " num-sum))) 2785 | ``` 2786 | #### Output 2787 | 2788 | The sum of the numbers is 45 2789 | 2790 | ### linq79: Sum - Projection 2791 | ```csharp 2792 | //c# 2793 | public void Linq79() 2794 | { 2795 | string[] words = { "cherry", "apple", "blueberry" }; 2796 | 2797 | double totalChars = words.Sum(w => w.Length); 2798 | 2799 | Console.WriteLine("There are a total of {0} characters in these words.", totalChars); 2800 | } 2801 | ``` 2802 | ```clojure 2803 | ;;clojure 2804 | (defn linq79 [] 2805 | (let [words ["cherry", "apple", "blueberry"] 2806 | total-chars (reduce + (map count words))] 2807 | (println "There are a total of" total-chars "characters in these words."))) 2808 | ``` 2809 | #### Output 2810 | 2811 | There are a total of 20 characters in these words. 2812 | 2813 | ### linq80: Sum - Grouped 2814 | ```csharp 2815 | //c# 2816 | public void Linq80() 2817 | { 2818 | List products = GetProductList(); 2819 | 2820 | var categories = 2821 | from p in products 2822 | group p by p.Category into g 2823 | select new { Category = g.Key, TotalUnitsInStock = g.Sum(p => p.UnitsInStock) }; 2824 | 2825 | ObjectDumper.Write(categories); 2826 | } 2827 | ``` 2828 | ```clojure 2829 | ;;clojure 2830 | (defn linq80 [] 2831 | (let [products products-list 2832 | categories 2833 | (->> products 2834 | (group-by :category) 2835 | (map #(identity 2836 | {:category (get % 0), 2837 | :total-units-in-stock (reduce + (map :units-in-stock (get % 1)))})))] 2838 | (doseq [x categories] (println x)))) 2839 | ``` 2840 | #### Output 2841 | 2842 | {:category Beverages, :total-units-in-stock 559} 2843 | {:category Condiments, :total-units-in-stock 507} 2844 | {:category Produce, :total-units-in-stock 100} 2845 | {:category Meat/Poultry, :total-units-in-stock 165} 2846 | {:category Seafood, :total-units-in-stock 701} 2847 | {:category Dairy Products, :total-units-in-stock 393} 2848 | {:category Confections, :total-units-in-stock 386} 2849 | {:category Grains/Cereals, :total-units-in-stock 308} 2850 | 2851 | ### linq81: Min - Simple 2852 | ```csharp 2853 | //c# 2854 | public void Linq81() 2855 | { 2856 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 2857 | 2858 | int minNum = numbers.Min(); 2859 | 2860 | Console.WriteLine("The minimum number is {0}.", minNum); 2861 | } 2862 | ``` 2863 | ```clojure 2864 | ;;clojure 2865 | (defn linq81 [] 2866 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 2867 | min-num (apply min numbers)] 2868 | (println "The minimum number is" min-num))) 2869 | ``` 2870 | #### Output 2871 | 2872 | The minimum number is 0 2873 | 2874 | ### linq82: Min - Projection 2875 | ```csharp 2876 | //c# 2877 | public void Linq82() 2878 | { 2879 | string[] words = { "cherry", "apple", "blueberry" }; 2880 | 2881 | int shortestWord = words.Min(w => w.Length); 2882 | 2883 | Console.WriteLine("The shortest word is {0} characters long.", shortestWord); 2884 | } 2885 | ``` 2886 | ```clojure 2887 | ;;clojure 2888 | (defn linq82 [] 2889 | (let [words ["cherry", "apple", "blueberry"] 2890 | shortest-word (apply min (map count words))] 2891 | (println "The shortest word is" shortest-word "characters long."))) 2892 | ``` 2893 | #### Output 2894 | 2895 | The shortest word is 5 characters long. 2896 | 2897 | ### linq83: Min - Grouped 2898 | ```csharp 2899 | //c# 2900 | public void Linq83() 2901 | { 2902 | List products = GetProductList(); 2903 | 2904 | var categories = 2905 | from p in products 2906 | group p by p.Category into g 2907 | select new { Category = g.Key, CheapestPrice = g.Min(p => p.UnitPrice) }; 2908 | 2909 | ObjectDumper.Write(categories); 2910 | } 2911 | ``` 2912 | ```clojure 2913 | ;;clojure 2914 | (defn linq83 [] 2915 | (let [products products-list 2916 | categories 2917 | (->> products 2918 | (group-by :category) 2919 | (map #(identity {:category (first %), 2920 | :cheapest-price (apply min (map :unit-price (second %)))})))] 2921 | (doseq [c categories] (println c)))) 2922 | ``` 2923 | #### Output 2924 | 2925 | {:category Beverages, :cheapest-price 4.5} 2926 | {:category Condiments, :cheapest-price 10.0} 2927 | {:category Produce, :cheapest-price 10.0} 2928 | {:category Meat/Poultry, :cheapest-price 7.45} 2929 | {:category Seafood, :cheapest-price 6.0} 2930 | {:category Dairy Products, :cheapest-price 2.5} 2931 | {:category Confections, :cheapest-price 9.2} 2932 | {:category Grains/Cereals, :cheapest-price 7.0} 2933 | 2934 | ### linq84: Min - Elements 2935 | ```csharp 2936 | //c# 2937 | public void Linq84() 2938 | { 2939 | List products = GetProductList(); 2940 | 2941 | var categories = 2942 | from p in products 2943 | group p by p.Category into g 2944 | let minPrice = g.Min(p => p.UnitPrice) 2945 | select new { Category = g.Key, CheapestProducts = g.Where(p => p.UnitPrice == minPrice) }; 2946 | 2947 | ObjectDumper.Write(categories, 1); 2948 | } 2949 | ``` 2950 | ```clojure 2951 | ;;clojure 2952 | (defn linq84 [] 2953 | (let [products products-list 2954 | categories 2955 | (for [g (group-by :category products) 2956 | :let [min-price (apply min (map :unit-price (second g)))]] 2957 | {:category (first g) 2958 | :cheapest-products (for [p (second g) 2959 | :when (= (:unit-price p) min-price)] p)})] 2960 | (doseq [c categories] (println c)))) 2961 | ``` 2962 | #### Output 2963 | 2964 | {:category Beverages, :cheapest-products (#clj_linq.data.Product{:product-id 24, :product-name Guaraná Fantástica, :category Beverages, :unit-price 4.5, :units-in-stock 20})} 2965 | {:category Condiments, :cheapest-products (#clj_linq.data.Product{:product-id 3, :product-name Aniseed Syrup, :category Condiments, :unit-price 10.0, :units-in-stock 13})} 2966 | {:category Produce, :cheapest-products (#clj_linq.data.Product{:product-id 74, :product-name Longlife Tofu, :category Produce, :unit-price 10.0, :units-in-stock 4})} 2967 | {:category Meat/Poultry, :cheapest-products (#clj_linq.data.Product{:product-id 54, :product-name Tourtière, :category Meat/Poultry, :unit-price 7.45, :units-in-stock 21})} 2968 | {:category Seafood, :cheapest-products (#clj_linq.data.Product{:product-id 13, :product-name Konbu, :category Seafood, :unit-price 6.0, :units-in-stock 24})} 2969 | {:category Dairy Products, :cheapest-products (#clj_linq.data.Product{:product-id 33, :product-name Geitost, :category Dairy Products, :unit-price 2.5, :units-in-stock 112})} 2970 | {:category Confections, :cheapest-products (#clj_linq.data.Product{:product-id 19, :product-name Teatime Chocolate Biscuits, :category Confections, :unit-price 9.2, :units-in-stock 25})} 2971 | {:category Grains/Cereals, :cheapest-products (#clj_linq.data.Product{:product-id 52, :product-name Filo Mix, :category Grains/Cereals, :unit-price 7.0, :units-in-stock 38})} 2972 | 2973 | ### linq85: Max - Simple 2974 | ```csharp 2975 | //c# 2976 | public void Linq85() 2977 | { 2978 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 2979 | 2980 | int maxNum = numbers.Max(); 2981 | 2982 | Console.WriteLine("The maximum number is {0}.", maxNum); 2983 | } 2984 | ``` 2985 | ```clojure 2986 | ;;clojure 2987 | (defn linq85 [] 2988 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 2989 | max-num (apply max numbers)] 2990 | (println "The maximum number is" max-num))) 2991 | ``` 2992 | #### Output 2993 | 2994 | The maximum number is 9 2995 | 2996 | ### linq86: Max - Projection 2997 | ```csharp 2998 | //c# 2999 | public void Linq86() 3000 | { 3001 | string[] words = { "cherry", "apple", "blueberry" }; 3002 | 3003 | int longestLength = words.Max(w => w.Length); 3004 | 3005 | Console.WriteLine("The longest word is {0} characters long.", longestLength); 3006 | } 3007 | ``` 3008 | ```clojure 3009 | ;;clojure 3010 | (defn linq86 [] 3011 | (let [words ["cherry", "apple", "blueberry"] 3012 | longest-word (apply max (map count words))] 3013 | (println "The longest word is" longest-word "characters long."))) 3014 | ``` 3015 | #### Output 3016 | 3017 | The longest word is 9 characters long. 3018 | 3019 | ### linq87: Max - Grouped 3020 | ```csharp 3021 | //c# 3022 | public void Linq87() 3023 | { 3024 | List products = GetProductList(); 3025 | 3026 | var categories = 3027 | from p in products 3028 | group p by p.Category into g 3029 | select new { Category = g.Key, MostExpensivePrice = g.Max(p => p.UnitPrice) }; 3030 | 3031 | ObjectDumper.Write(categories); 3032 | } 3033 | ``` 3034 | ```clojure 3035 | ;;clojure 3036 | (defn linq87 [] 3037 | (let [products products-list 3038 | categories 3039 | (->> products 3040 | (group-by :category) 3041 | (map #(identity 3042 | {:category (get % 0), 3043 | :most-expensive-price (apply max (map :unit-price (get % 1)))})))] 3044 | (doseq [c categories] (println c)))) 3045 | ``` 3046 | #### Output 3047 | 3048 | {:category Beverages, :most-expensive-price 263.5} 3049 | {:category Condiments, :most-expensive-price 43.9} 3050 | {:category Produce, :most-expensive-price 53.0} 3051 | {:category Meat/Poultry, :most-expensive-price 123.79} 3052 | {:category Seafood, :most-expensive-price 62.5} 3053 | {:category Dairy Products, :most-expensive-price 55.0} 3054 | {:category Confections, :most-expensive-price 81.0} 3055 | {:category Grains/Cereals, :most-expensive-price 38.0} 3056 | 3057 | ### linq88: Max - Elements 3058 | ```csharp 3059 | //c# 3060 | public void Linq88() 3061 | { 3062 | List products = GetProductList(); 3063 | 3064 | var categories = 3065 | from p in products 3066 | group p by p.Category into g 3067 | let maxPrice = g.Max(p => p.UnitPrice) 3068 | select new { Category = g.Key, MostExpensiveProducts = g.Where(p => p.UnitPrice == maxPrice) }; 3069 | 3070 | ObjectDumper.Write(categories, 1); 3071 | } 3072 | ``` 3073 | ```clojure 3074 | ;;clojure 3075 | (defn linq88 [] 3076 | (let [products products-list 3077 | categories 3078 | (for [g (group-by :category products) 3079 | :let [max-price (apply max (map :unit-price (second g)))]] 3080 | {:category (first g) 3081 | :most-expensive-products 3082 | (for [p (second g) :when (= (:unit-price p) max-price)] p)})] 3083 | (doseq [c categories] (println c)))) 3084 | ``` 3085 | #### Output 3086 | 3087 | {:category Beverages, :most-expensive-products (#clj_linq.data.Product{:product-id 38, :product-name Côte de Blaye, :category Beverages, :unit-price 263.5, :units-in-stock 17})} 3088 | {:category Condiments, :most-expensive-products (#clj_linq.data.Product{:product-id 63, :product-name Vegie-spread, :category Condiments, :unit-price 43.9, :units-in-stock 24})} 3089 | {:category Produce, :most-expensive-products (#clj_linq.data.Product{:product-id 51, :product-name Manjimup Dried Apples, :category Produce, :unit-price 53.0, :units-in-stock 20})} 3090 | {:category Meat/Poultry, :most-expensive-products (#clj_linq.data.Product{:product-id 29, :product-name Thüringer Rostbratwurst, :category Meat/Poultry, :unit-price 123.79, :units-in-stock 0})} 3091 | {:category Seafood, :most-expensive-products (#clj_linq.data.Product{:product-id 18, :product-name Carnarvon Tigers, :category Seafood, :unit-price 62.5, :units-in-stock 42})} 3092 | {:category Dairy Products, :most-expensive-products (#clj_linq.data.Product{:product-id 59, :product-name Raclette Courdavault, :category Dairy Products, :unit-price 55.0, :units-in-stock 79})} 3093 | {:category Confections, :most-expensive-products (#clj_linq.data.Product{:product-id 20, :product-name Sir Rodney's Marmalade, :category Confections, :unit-price 81.0, :units-in-stock 40})} 3094 | {:category Grains/Cereals, :most-expensive-products (#clj_linq.data.Product{:product-id 56, :product-name Gnocchi di nonna Alice, :category Grains/Cereals, :unit-price 38.0, :units-in-stock 21})} 3095 | 3096 | ### linq89: Average - Simple 3097 | ```csharp 3098 | //c# 3099 | public void Linq89() 3100 | { 3101 | int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 3102 | 3103 | double averageNum = numbers.Average(); 3104 | 3105 | Console.WriteLine("The average number is {0}.", averageNum); 3106 | } 3107 | ``` 3108 | ```clojure 3109 | ;;clojure 3110 | (defn linq89 [] 3111 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 3112 | avg (average numbers)] 3113 | (println "The average number is" avg))) 3114 | ``` 3115 | #### Output 3116 | 3117 | The average number is 9/2 3118 | 3119 | ### linq90: Average - Projection 3120 | ```csharp 3121 | //c# 3122 | public void Linq90() 3123 | { 3124 | string[] words = { "cherry", "apple", "blueberry" }; 3125 | 3126 | double averageLength = words.Average(w => w.Length); 3127 | 3128 | Console.WriteLine("The average word length is {0} characters.", averageLength); 3129 | } 3130 | ``` 3131 | ```clojure 3132 | ;;clojure 3133 | (defn linq90 [] 3134 | (let [words ["cherry", "apple", "blueberry"] 3135 | average-length (average (map count words))] 3136 | (println "The average word length is" average-length "characters."))) 3137 | ``` 3138 | #### Output 3139 | 3140 | The average word length is 20/3 characters. 3141 | 3142 | ### linq91: Average - Grouped 3143 | ```csharp 3144 | //c# 3145 | public void Linq91() 3146 | { 3147 | List products = GetProductList(); 3148 | 3149 | var categories = 3150 | from p in products 3151 | group p by p.Category into g 3152 | select new { Category = g.Key, AveragePrice = g.Average(p => p.UnitPrice) }; 3153 | 3154 | ObjectDumper.Write(categories); 3155 | } 3156 | ``` 3157 | ```clojure 3158 | ;;clojure 3159 | (defn linq91 [] 3160 | (let [products products-list 3161 | categories 3162 | (for [g (group-by :category products)] 3163 | {:category (first g), 3164 | :average-price (average (map :unit-price (second g)))})] 3165 | (doseq [c categories] (println c)))) 3166 | ``` 3167 | #### Output 3168 | 3169 | {:category Beverages, :average-price 37.979166666666664} 3170 | {:category Condiments, :average-price 23.0625} 3171 | {:category Produce, :average-price 32.37} 3172 | {:category Meat/Poultry, :average-price 54.00666666666667} 3173 | {:category Seafood, :average-price 20.6825} 3174 | {:category Dairy Products, :average-price 28.73} 3175 | {:category Confections, :average-price 25.16} 3176 | {:category Grains/Cereals, :average-price 20.25} 3177 | 3178 | ### linq92: Aggregate - Simple 3179 | ```csharp 3180 | //c# 3181 | public void Linq92() 3182 | { 3183 | double[] doubles = { 1.7, 2.3, 1.9, 4.1, 2.9 }; 3184 | 3185 | double product = doubles.Aggregate((runningProduct, nextFactor) => runningProduct * nextFactor); 3186 | 3187 | Console.WriteLine("Total product of all numbers: {0}", product); 3188 | } 3189 | ``` 3190 | ```clojure 3191 | ;;clojure 3192 | (defn linq92 [] 3193 | (let [dbls [1.7 2.3 1.9 4.1 2.9] 3194 | product (reduce * dbls)] 3195 | (println "Total product of all numbers:" product))) 3196 | ``` 3197 | #### Output 3198 | 3199 | Total product of all numbers: 88.33080999999999 3200 | 3201 | ### linq93: Aggregate - Seed 3202 | ```csharp 3203 | //c# 3204 | public void Linq93() 3205 | { 3206 | double startBalance = 100.0; 3207 | 3208 | int[] attemptedWithdrawals = { 20, 10, 40, 50, 10, 70, 30 }; 3209 | 3210 | double endBalance = 3211 | attemptedWithdrawals.Aggregate(startBalance, 3212 | (balance, nextWithdrawal) => 3213 | ((nextWithdrawal <= balance) ? (balance - nextWithdrawal) : balance)); 3214 | 3215 | Console.WriteLine("Ending balance: {0}", endBalance); 3216 | } 3217 | ``` 3218 | ```clojure 3219 | ;;clojure 3220 | (defn linq93 [] 3221 | (let [start-balance 100 3222 | attempted-withdrawls [20 10 40 50 10 70 30] 3223 | end-balance (reduce #(identity (if (<= %2 %1) (- %1 %2) %1)) 3224 | start-balance attempted-withdrawls)] 3225 | (println "Ending balance:" end-balance))) 3226 | ``` 3227 | #### Output 3228 | 3229 | Ending balance: 20 3230 | 3231 | 3232 | LINQ - Miscellaneous Operators 3233 | ------------------------------ 3234 | 3235 | ### linq94: Concat - 1 3236 | ```csharp 3237 | //c# 3238 | public void Linq94() 3239 | { 3240 | int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 }; 3241 | int[] numbersB = { 1, 3, 5, 7, 8 }; 3242 | 3243 | var allNumbers = numbersA.Concat(numbersB); 3244 | 3245 | Console.WriteLine("All numbers from both arrays:"); 3246 | foreach (var n in allNumbers) 3247 | { 3248 | Console.WriteLine(n); 3249 | } 3250 | } 3251 | ``` 3252 | ```clojure 3253 | ;;clojure 3254 | (defn linq94 [] 3255 | (let [numbers-a [0 2 4 5 6 8 9] 3256 | numbers-b [1 3 5 7 8] 3257 | all-numbers (flatten [numbers-a numbers-b])] 3258 | (println "All numbers from both arrays:") 3259 | (doseq [n all-numbers] (println n)))) 3260 | ``` 3261 | #### Output 3262 | 3263 | All numbers from both arrays: 3264 | 0 3265 | 2 3266 | 4 3267 | 5 3268 | 6 3269 | 8 3270 | 9 3271 | 1 3272 | 3 3273 | 5 3274 | 7 3275 | 8 3276 | 3277 | ### linq95: Concat - 2 3278 | ```csharp 3279 | //c# 3280 | public void Linq95() 3281 | { 3282 | List customers = GetCustomerList(); 3283 | List products = GetProductList(); 3284 | 3285 | var customerNames = 3286 | from c in customers 3287 | select c.CompanyName; 3288 | var productNames = 3289 | from p in products 3290 | select p.ProductName; 3291 | 3292 | var allNames = customerNames.Concat(productNames); 3293 | 3294 | Console.WriteLine("Customer and product names:"); 3295 | foreach (var n in allNames) 3296 | { 3297 | Console.WriteLine(n); 3298 | } 3299 | } 3300 | ``` 3301 | ```clojure 3302 | ;;clojure 3303 | (defn linq95 [] 3304 | (let [products products-list 3305 | customers customers-list 3306 | customer-names (map :company-name customers) 3307 | product-names (map :product-name products) 3308 | all-names (flatten [customer-names product-names])] 3309 | (println "Customer and product names:") 3310 | (doseq [x all-names] (println x)))) 3311 | ``` 3312 | #### Output 3313 | 3314 | Customer and product names: 3315 | Alfreds Futterkiste 3316 | Ana Trujillo Emparedados y helados 3317 | Antonio Moreno Taquería 3318 | Around the Horn 3319 | Berglunds snabbköp 3320 | Blauer See Delikatessen 3321 | ... 3322 | 3323 | ### linq96: EqualAll - 1 3324 | ```csharp 3325 | //c# 3326 | public void Linq96() 3327 | { 3328 | var wordsA = new string[] { "cherry", "apple", "blueberry" }; 3329 | var wordsB = new string[] { "cherry", "apple", "blueberry" }; 3330 | 3331 | bool match = wordsA.SequenceEqual(wordsB); 3332 | 3333 | Console.WriteLine("The sequences match: {0}", match); 3334 | } 3335 | ``` 3336 | ```clojure 3337 | ;;clojure 3338 | (defn linq96 [] 3339 | (let [words-a ["cherry" "apple" "blueberry"] 3340 | words-b ["cherry" "apple" "blueberry"] 3341 | match (= words-a words-b)] 3342 | (println "The sequences match:" match))) 3343 | ``` 3344 | #### Output 3345 | 3346 | The sequences match: true 3347 | 3348 | ### linq97: EqualAll - 2 3349 | ```csharp 3350 | //c# 3351 | public void Linq97() 3352 | { 3353 | var wordsA = new string[] { "cherry", "apple", "blueberry" }; 3354 | var wordsB = new string[] { "apple", "blueberry", "cherry" }; 3355 | 3356 | bool match = wordsA.SequenceEqual(wordsB); 3357 | 3358 | Console.WriteLine("The sequences match: {0}", match); 3359 | } 3360 | ``` 3361 | ```clojure 3362 | ;;clojure 3363 | (defn linq97 [] 3364 | (let [words-a ["cherry" "apple" "blueberry"] 3365 | words-b ["apple" "blueberry" "cherry"] 3366 | match (= words-a words-b)] 3367 | (println "The sequences match:" match))) 3368 | ``` 3369 | #### Output 3370 | 3371 | The sequences match: false 3372 | 3373 | 3374 | LINQ - Query Execution 3375 | ---------------------- 3376 | 3377 | ### linq99: Deferred Execution 3378 | ```csharp 3379 | //c# 3380 | public void Linq99() 3381 | { 3382 | // Sequence operators form first-class queries that 3383 | // are not executed until you enumerate over them. 3384 | 3385 | int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 3386 | 3387 | int i = 0; 3388 | var q = 3389 | from n in numbers 3390 | select ++i; 3391 | 3392 | // Note, the local variable 'i' is not incremented 3393 | // until each element is evaluated (as a side-effect): 3394 | foreach (var v in q) 3395 | { 3396 | Console.WriteLine("v = {0}, i = {1}", v, i); 3397 | } 3398 | } 3399 | ``` 3400 | ```clojure 3401 | ;;clojure 3402 | (defn linq99 [] 3403 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 3404 | i (atom 0) 3405 | q (map (fn [x] (swap! i inc)) (range 10))] 3406 | (println @i (count q) @i))) 3407 | ``` 3408 | #### Output 3409 | 3410 | 0 10 10 3411 | 3412 | ### linq100: Immediate Execution 3413 | ```csharp 3414 | //c# 3415 | public void Linq100() 3416 | { 3417 | // Methods like ToList() cause the query to be 3418 | // executed immediately, caching the results. 3419 | 3420 | int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 3421 | 3422 | int i = 0; 3423 | var q = ( 3424 | from n in numbers 3425 | select ++i) 3426 | .ToList(); 3427 | 3428 | // The local variable i has already been fully 3429 | // incremented before we iterate the results: 3430 | foreach (var v in q) 3431 | { 3432 | Console.WriteLine("v = {0}, i = {1}", v, i); 3433 | } 3434 | } 3435 | ``` 3436 | ```clojure 3437 | ;;clojure 3438 | (defn linq100 [] 3439 | (let [numbers [5 4 1 3 9 8 6 7 2 0] 3440 | i (atom 0) 3441 | q (into [] (map (fn [x] (swap! i inc)) (range 10)))] 3442 | (println @i (count q) @i))) 3443 | ``` 3444 | #### Output 3445 | 3446 | 10 10 10 3447 | 3448 | ### linq101: Query Reuse 3449 | ```csharp 3450 | //c# 3451 | public void Linq101() 3452 | { 3453 | // Deferred execution lets us define a query once 3454 | // and then reuse it later after data changes. 3455 | 3456 | int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 3457 | var lowNumbers = 3458 | from n in numbers 3459 | where n <= 3 3460 | select n; 3461 | 3462 | Console.WriteLine("First run numbers <= 3:"); 3463 | foreach (int n in lowNumbers) 3464 | { 3465 | Console.WriteLine(n); 3466 | } 3467 | 3468 | for (int i = 0; i < 10; i++) 3469 | { 3470 | numbers[i] = -numbers[i]; 3471 | } 3472 | 3473 | // During this second run, the same query object, 3474 | // lowNumbers, will be iterating over the new state 3475 | // of numbers[], producing different results: 3476 | Console.WriteLine("Second run numbers <= 3:"); 3477 | foreach (int n in lowNumbers) 3478 | { 3479 | Console.WriteLine(n); 3480 | } 3481 | } 3482 | ``` 3483 | ```clojure 3484 | ;;clojure 3485 | (defn linq101 [] 3486 | (def ^:dynamic numbers [5 4 1 3 9 8 6 7 2 0]) 3487 | 3488 | (defn low-numbers [] 3489 | (filter #(<= % 3) numbers)) 3490 | 3491 | (println "First run numbers <= 3:") 3492 | (doseq [n (low-numbers)] (println n)) 3493 | 3494 | (println "Second run numbers <= 3") 3495 | (binding [numbers (map #(* -1 %) numbers)] 3496 | (doseq [n (low-numbers)] (println n)))) 3497 | ``` 3498 | #### Output 3499 | 3500 | First run numbers <= 3: 3501 | 1 3502 | 3 3503 | 2 3504 | 0 3505 | Second run numbers <= 3 3506 | -5 3507 | -4 3508 | -1 3509 | -3 3510 | -9 3511 | -8 3512 | -6 3513 | -7 3514 | -2 3515 | 0 3516 | 3517 | 3518 | LINQ - Join Operators 3519 | --------------------- 3520 | 3521 | ### Clojure utils added 3522 | 3523 | ```clojure 3524 | (defn join [coll with-coll matcher] 3525 | (map (fn [x] {:key x :items (filter (fn [y] (matcher x y)) with-coll)}) 3526 | coll)) 3527 | ``` 3528 | 3529 | ### linq102: Cross Join 3530 | ```csharp 3531 | //c# 3532 | public void Linq102() 3533 | { 3534 | string[] categories = new string[]{ 3535 | "Beverages", 3536 | "Condiments", 3537 | "Vegetables", 3538 | "Dairy Products", 3539 | "Seafood" }; 3540 | 3541 | List products = GetProductList(); 3542 | 3543 | var q = 3544 | from c in categories 3545 | join p in products on c equals p.Category 3546 | select new { Category = c, p.ProductName }; 3547 | 3548 | foreach (var v in q) 3549 | { 3550 | Console.WriteLine(v.ProductName + ": " + v.Category); 3551 | } 3552 | } 3553 | ``` 3554 | ```clojure 3555 | ;;clojure 3556 | (defn linq102 [] 3557 | (let [categories 3558 | ["Beverages", "Condiments", "Vegetables", "Dairy Products", "Seafood"] 3559 | products products-list 3560 | q (for [pc (join-group categories products #(= %1 (:category %2))) 3561 | x (:items pc)] 3562 | {:category (:key pc), :product-name (:product-name x)})] 3563 | (doseq [v q] 3564 | (println (:product-name v) ":" (:category v))))) 3565 | ``` 3566 | #### Output 3567 | 3568 | Chai : Beverages 3569 | Chang : Beverages 3570 | Guaraná Fantástica : Beverages 3571 | Sasquatch Ale : Beverages 3572 | Steeleye Stout : Beverages 3573 | Côte de Blaye : Beverages 3574 | Chartreuse verte : Beverages 3575 | Ipoh Coffee : Beverages 3576 | ... 3577 | 3578 | ### linq103: Group Join 3579 | ```csharp 3580 | //c# 3581 | public void Linq103() 3582 | { 3583 | string[] categories = new string[]{ 3584 | "Beverages", 3585 | "Condiments", 3586 | "Vegetables", 3587 | "Dairy Products", 3588 | "Seafood" }; 3589 | 3590 | List products = GetProductList(); 3591 | 3592 | var q = 3593 | from c in categories 3594 | join p in products on c equals p.Category into ps 3595 | select new { Category = c, Products = ps }; 3596 | 3597 | foreach (var v in q) 3598 | { 3599 | Console.WriteLine(v.Category + ":"); 3600 | foreach (var p in v.Products) 3601 | { 3602 | Console.WriteLine(" " + p.ProductName); 3603 | } 3604 | } 3605 | } 3606 | ``` 3607 | ```clojure 3608 | ;;clojure 3609 | (defn linq103 [] 3610 | (let [categories ["Beverages", "Condiments", "Vegetables", "Dairy Products", "Seafood"] 3611 | products products-list 3612 | q (for [pc (join-group categories products #(= %1 (:category %2)))] 3613 | {:category (:key pc), :products (:items pc)})] 3614 | (doseq [pc q] 3615 | (println (:category pc)) 3616 | (doseq [product (:products pc)] 3617 | (println " " (:product-name product)))))) 3618 | ``` 3619 | #### Output 3620 | 3621 | Beverages 3622 | Chai 3623 | Chang 3624 | Guaraná Fantástica 3625 | Sasquatch Ale 3626 | Steeleye Stout 3627 | Côte de Blaye 3628 | Chartreuse verte 3629 | Ipoh Coffee 3630 | Laughing Lumberjack Lager 3631 | Outback Lager 3632 | Rhönbräu Klosterbier 3633 | Lakkalikööri 3634 | Condiments 3635 | Aniseed Syrup 3636 | Chef Anton's Cajun Seasoning 3637 | Chef Anton's Gumbo Mix 3638 | Grandma's Boysenberry Spread 3639 | Northwoods Cranberry Sauce 3640 | Genen Shouyu 3641 | Gula Malacca 3642 | Sirop d'érable 3643 | Vegie-spread 3644 | Louisiana Fiery Hot Pepper Sauce 3645 | Louisiana Hot Spiced Okra 3646 | Original Frankfurter grüne Soße 3647 | ... 3648 | 3649 | ### linq104: Cross Join with Group Join 3650 | ```csharp 3651 | //c# 3652 | public void Linq104() 3653 | { 3654 | string[] categories = new string[]{ 3655 | "Beverages", 3656 | "Condiments", 3657 | "Vegetables", 3658 | "Dairy Products", 3659 | "Seafood" }; 3660 | 3661 | List products = GetProductList(); 3662 | 3663 | var q = 3664 | from c in categories 3665 | join p in products on c equals p.Category into ps 3666 | from p in ps 3667 | select new { Category = c, p.ProductName }; 3668 | 3669 | foreach (var v in q) 3670 | { 3671 | Console.WriteLine(v.ProductName + ": " + v.Category); 3672 | } 3673 | } 3674 | ``` 3675 | ```clojure 3676 | ;;clojure 3677 | (defn linq104 [] 3678 | (let [categories 3679 | ["Beverages", "Condiments", "Vegetables", "Dairy Products", "Seafood"] 3680 | products products-list 3681 | q (for [pc (join-group categories products #(= %1 (:category %2))) 3682 | p (:items pc)] 3683 | {:category (:key pc), 3684 | :product-name (:product-name p)})] 3685 | (doseq [p q] 3686 | (println (:product-name p) ":" (:category p))))) 3687 | ``` 3688 | #### Output 3689 | 3690 | Chai : Beverages 3691 | Chang : Beverages 3692 | Guaraná Fantástica : Beverages 3693 | Sasquatch Ale : Beverages 3694 | Steeleye Stout : Beverages 3695 | Côte de Blaye : Beverages 3696 | Chartreuse verte : Beverages 3697 | Ipoh Coffee : Beverages 3698 | Laughing Lumberjack Lager : Beverages 3699 | Outback Lager : Beverages 3700 | Rhönbräu Klosterbier : Beverages 3701 | Lakkalikööri : Beverages 3702 | Aniseed Syrup : Condiments 3703 | Chef Anton's Cajun Seasoning : Condiments 3704 | Chef Anton's Gumbo Mix : Condiments 3705 | ... 3706 | 3707 | ### linq105: Left Outer Join 3708 | ```csharp 3709 | //c# 3710 | public void Linq105() 3711 | { 3712 | string[] categories = new string[]{ 3713 | "Beverages", 3714 | "Condiments", 3715 | "Vegetables", 3716 | "Dairy Products", 3717 | "Seafood" }; 3718 | 3719 | List products = GetProductList(); 3720 | 3721 | var q = 3722 | from c in categories 3723 | join p in products on c equals p.Category into ps 3724 | from p in ps.DefaultIfEmpty() 3725 | select new { Category = c, ProductName = p == null ? "(No products)" : p.ProductName }; 3726 | 3727 | foreach (var v in q) 3728 | { 3729 | Console.WriteLine(v.ProductName + ": " + v.Category); 3730 | } 3731 | } 3732 | ``` 3733 | ```clojure 3734 | ;;clojure 3735 | (defn linq105 [] 3736 | (let [categories 3737 | ["Beverages", "Condiments", "Vegetables", "Dairy Products", "Seafood"] 3738 | products products-list 3739 | q (flatten 3740 | (for [pc (join-group categories products #(= %1 (:category %2)))] 3741 | (if (empty? (:items pc)) 3742 | {:category (:key pc), :product-name "(No products)"} 3743 | (for [p (:items pc)] 3744 | {:category (:key pc), 3745 | :product-name (:product-name p)}))))] 3746 | (doseq [p q] 3747 | (println (:product-name p) ":" (:category p))))) 3748 | ``` 3749 | #### Output 3750 | 3751 | Chai: Beverages 3752 | Chang: Beverages 3753 | Guaraná Fantástica: Beverages 3754 | Sasquatch Ale: Beverages 3755 | Steeleye Stout: Beverages 3756 | Côte de Blaye: Beverages 3757 | Chartreuse verte: Beverages 3758 | Ipoh Coffee: Beverages 3759 | Laughing Lumberjack Lager: Beverages 3760 | Outback Lager: Beverages 3761 | Rhönbräu Klosterbier: Beverages 3762 | Lakkalikööri: Beverages 3763 | Aniseed Syrup: Condiments 3764 | Chef Anton's Cajun Seasoning: Condiments 3765 | Chef Anton's Gumbo Mix: Condiments 3766 | Grandma's Boysenberry Spread: Condiments 3767 | Northwoods Cranberry Sauce: Condiments 3768 | Genen Shouyu: Condiments 3769 | Gula Malacca: Condiments 3770 | Sirop d'érable: Condiments 3771 | Vegie-spread: Condiments 3772 | Louisiana Fiery Hot Pepper Sauce: Condiments 3773 | Louisiana Hot Spiced Okra: Condiments 3774 | Original Frankfurter grüne Soße: Condiments 3775 | (No products): Vegetables 3776 | ... 3777 | 3778 | 3779 | ### Contributors 3780 | 3781 | - [mythz](https://github.com/mythz) (Demis Bellot) 3782 | --------------------------------------------------------------------------------