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