{"id":32977203,"url":"https://github.com/slazyk/SINQ","last_synced_at":"2025-11-16T06:00:53.195Z","repository":{"id":62453765,"uuid":"21183104","full_name":"slazyk/SINQ","owner":"slazyk","description":"LINQ for Swift - Swift Integrated Query","archived":false,"fork":false,"pushed_at":"2019-05-03T06:59:01.000Z","size":76,"stargazers_count":268,"open_issues_count":2,"forks_count":27,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-11-12T02:22:43.581Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/slazyk.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-06-24T22:40:03.000Z","updated_at":"2025-10-27T20:09:21.000Z","dependencies_parsed_at":"2022-11-01T23:46:13.745Z","dependency_job_id":null,"html_url":"https://github.com/slazyk/SINQ","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/slazyk/SINQ","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slazyk%2FSINQ","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slazyk%2FSINQ/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slazyk%2FSINQ/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slazyk%2FSINQ/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/slazyk","download_url":"https://codeload.github.com/slazyk/SINQ/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slazyk%2FSINQ/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":284667476,"owners_count":27043890,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-16T02:00:05.974Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-11-13T06:00:32.663Z","updated_at":"2025-11-16T06:00:53.178Z","avatar_url":"https://github.com/slazyk.png","language":"Swift","funding_links":[],"categories":["Libraries","Implementations"],"sub_categories":["[Swift](https://developer.apple.com/swift)","Miscs"],"readme":"# SINQ - Swift Integrated Query\n\nSwift has generic Collections and Sequences as well as some universal free functions to work with them. What is missing is a fluent interface that would make working with them easy¹ - like list comprehensions in many languages or LINQ in .NET. The operations should: require **no typecasts**, be **easily chained**, work on **any sequences**, be **performed lazily** where possible.\n\n## Overview\n\nSINQ (or LINQ for Swift) is a Swift library for working with sequences / collections. It is, as name suggests, modelled after LINQ, but it is not necessarily intended to be a LINQ port. The library is still under development, just as Swift is. Any contributions, both in terms of suggestions/ideas or actual code are welcome.\n\nSINQ is brought to you by Leszek Ślażyński (slazyk), you can follow me on [twitter](https://twitter.com/slazyk) and [github](https://github.com/slazyk). Be sure to check out [Observable-Swift](https://github.com/slazyk/Observable-Swift) my other library that implements value observing and events. \n\n## Examples\n\nThe main goal of SINQ is to provide a *fluent* interface for working with collections. The way it tries to accomplish that is with **chaining of methods**. Most of the operations are **performed lazily**, i.e. computations are deferred and done only for the part of the result you enumerate. Everything is typed - **no typecasts required**. Examples:\n\n```swift\nlet nums1 = from([1, 4, 2, 3, 5]).whereTrue{ $0 \u003e 2 }.orderBy{ $0 }.select{ 2 * $0 }\n// or less (linq | sql)-esque \nlet nums2 = sinq([1, 4, 2, 3, 5]).filter{ $0 \u003e 2 }.orderBy{ $0 }.map{ 2 * $0 }\n\n// path1 : String = ..., path2: String = ...\nlet commonComponents = sinq(path1.pathComponents)\n    .zip(path2.pathComponents) { ($0, $1) }\n    .takeWhile { $0 == $1 }\n    .count()\n\nlet prefixLength = sinq(path1).zip(path2){ ($0, $1) }.takeWhile{ $0 == $1 }.count()\n\n// available : String[] = ..., blacklist : String[] = ...\nlet next = sinq(available).except(blacklist){ $0 }.firstOrDefault(\"unknown\")\n\n// employees : Employee[] = ...\n\nlet headCnt = sinq(employees).groupBy{ $0.manager }.map{ ($0.key, $0.values.count()) }\n\nlet allTasks = from(employees).selectMany{ $0.tasks }.orderBy{ $0.priority }\n\nlet elite1 = sinq(employees).whereTrue{ $0.salary \u003e 1337 }.orderBy{ $0.salary }\nlet elite2 = from(employees).orderBy{ $0.salary }.takeWhile{ $0.salary \u003e 1337 }\n\n// products : Product[] = ..., categories : Category[] = ...\n\nlet breadcrumbs = sinq(categories).join(inner: products,\n                                     outerKey: { $0.id },\n                                     innerKey: { $0.categoryId },\n                                       result: { \"\\($0.name) / \\($1.name)\" })\n\n```\n\nPlease note that the results are not cached, i.e. looping twice over result of `orderBy(...)` will perform two sorts. If you want to use results multiple times, you can get always array with `toArray()`.\n\nIt uses `SinqSequence\u003cT\u003e` wrapper struct in order to do that, **you can wrap any `Sequence`** by simply `sinq(seq)`, `from(seq)`, or `SinqSequence(seq)`. This wrapper is introduced because Swift does not allow for adding methods to protocols (like `Sequence`) and because extending existing `SequenceOf\u003cT\u003e` causes linker errors.\n\n*While I do try to follow cocoa-like naming and spelling conventions, while also keeping the LINQ naming where reasonable, I refuse to call the struct `SINQSequence\u003cT\u003e` or `SSequence\u003cT\u003e`.*\n\n## Installation\n\nYou can use either [CocoaPods](https://cocoapods.org/) or [Carthage](https://github.com/Carthage/Carthage) to install SINQ.\n\nOtherwise, the easiest option to use SINQ in your project is to clone this repo and add SINQ.xcodeproj to your project/workspace and then add SINQ.framework to frameworks for your target.\n\nAfter that you just `import SINQ`.\n\n## List of methods\n\n##### `aggregate` / `reduce` - combine all the elements of the sequence into a result\n```swift\naggregate(combine: (T, T) -\u003e T) -\u003e T\naggregate\u003cR\u003e(initial: R, combine: (R, T) -\u003e R) -\u003e R\naggregate\u003cC, R\u003e(initial: C, combine: (C, T) -\u003e C, result: C -\u003e R) -\u003e R\n```\n##### `all` - check if a predicate is true for all the elements\n```swift\nall(predicate: T -\u003e Bool) -\u003e Bool\n```\n##### `any` - check if not empty, or if a predicate is true for any object\n```swift\nany() -\u003e Bool      \nany(predicate: T -\u003e Bool) -\u003e Bool\n```\n##### `concat` - create a sequence concatenating two sequences\n```swift\nconcat\u003cS: Sequence\u003e(other: S) -\u003e SinqSequence\u003cT\u003e\n```\n##### `contains` - check if the sequence contains an element\n```swift\ncontains(value: T, equality: (T, T) -\u003e Bool) -\u003e Bool\ncontains\u003cK: Equatable\u003e(value: T, key: T -\u003e K) -\u003e Bool\n```\n##### `count` - count the elements in the sequence\n```swift\nfunc count() -\u003e Int\n```  \n##### `distinct` - create a sequence with unique elements, in order\n```swift\ndistinct(equality: (T, T) -\u003e Bool) -\u003e SinqSequence\u003cT\u003e\ndistinct\u003cK: Hashable\u003e(key: T -\u003e K) -\u003e SinqSequence\u003cT\u003e\n```\n##### `each` - iterate over the sequence\n```swift\neach(function: T -\u003e ()) -\u003e ()  \n```\n##### `elementAt` - get element at given index from the sequence\n```swift\nelementAtOrNil(index: Int) -\u003e T?  \nelementAt(index: Int) -\u003e T\nelementAt(index: Int, orDefault: T) -\u003e T\n```\n##### `except` - create sequence with unique elements, excluding given\n```swift\nexcept\u003cS: Sequence\u003e(sequence: S, equality: (T, T) -\u003e Bool) -\u003e SinqSequence\u003cT\u003e \nexcept\u003cS: Sequence, K: Hashable\u003e(sequence: S, key: T -\u003e K) -\u003e SinqSequence\u003cT\u003e  \n```\n##### `first` - get first element of the sequence [satisfying a predicate]\n```swift\nfirst() -\u003e T\nfirstOrNil() -\u003e T?\nfirst(predicate: T -\u003e Bool) -\u003e T\nfirstOrDefault(defaultElement: T) -\u003e T\nfirstOrNil(predicate: T -\u003e Bool) -\u003e T?\nfirstOrDefault(defaultElement: T, predicate: T -\u003e Bool) -\u003e T\n```\n##### `groupBy` - create a sequence grouping elements by given key\n```swift\ngroupBy\u003cK: Hashable\u003e(key: T -\u003e K) -\u003e SinqSequence\u003cGrouping\u003cK, T\u003e\u003e\ngroupBy\u003cK: Hashable, V\u003e(key: T -\u003e K, element: T -\u003e V) -\u003e SinqSequence\u003cGrouping\u003cK, V\u003e\u003e\ngroupBy\u003cK: Hashable, V, R\u003e(key: T -\u003e K, element: T -\u003e V, result: (K, SinqSequence\u003cV\u003e) -\u003e R) -\u003e SinqSequence\u003cR\u003e\n```\n##### `groupJoin` - create a sequence joining two sequences with grouping\n```swift\ngroupJoin\u003cS: Sequence, K: Hashable\u003e\n\t(#inner: S, outerKey: T -\u003e K, innerKey: S.E -\u003e K)\n\t-\u003e SinqSequence\u003cGrouping\u003cT, S.E\u003e\u003e\ngroupJoin\u003cS: Sequence, K: Hashable, R\u003e\n\t(#inner: S, outerKey: T -\u003e K, innerKey: S.E -\u003e K,\n \t result: (T, SinqSequence\u003cS.E\u003e) -\u003e R) -\u003e SinqSequence\u003cR\u003e\n```\n##### `intersect` - create a sequence with unique elements present in both sequences\n```swift\nintersect\u003cS: Sequence\u003e(sequence: S, equality: (T, T) -\u003e Bool) -\u003e SinqSequence\u003cT\u003e\nintersect\u003cS: Sequence, K: Hashable\u003e(sequence: S, key: T -\u003e K) -\u003e SinqSequence\u003cT\u003e\n```\n##### `join` - create a sequence joining two sequences without grouping\n```swift\njoin\u003cS: Sequence, K: Hashable, R\u003e\n\t(#inner: S, outerKey: T -\u003e K, innerKey: S.E -\u003e K,\n     result: (T, S.E) -\u003e R) -\u003e SinqSequence\u003cR\u003e\njoin\u003cS: Sequence, K: Hashable\u003e\n    (#inner: S, outerKey: T -\u003e K, innerKey: S.E -\u003e K)\n    -\u003e SinqSequence\u003c(T, S.E)\u003e\n```\n##### `last` - return last element in the sequence [satisfying a predicate] \n```swift\nlast() -\u003e T\nlastOrNil() -\u003e T?\nlast(predicate: T -\u003e Bool) -\u003e T\nlastOrNil(predicate: T -\u003e Bool) -\u003e T?\nlastOrDefault(defaultElement: T) -\u003e T\nlastOrDefault(defaultElement: T, predicate: T -\u003e Bool) -\u003e T\n```\n##### `min` / `max` - return the minimum/maximum value of a function for the sequence    \n```swift\nmin\u003cR: Comparable\u003e(key: T -\u003e R) -\u003e R\nmax\u003cR: Comparable\u003e(key: T -\u003e R) -\u003e R\n```\n##### `argmin` / `argmax` - return the element for which the function has the minimum/maximum value\n```swift\nargmin\u003cR: Comparable\u003e(key: T -\u003e R) -\u003e T\nargmax\u003cR: Comparable\u003e(key: T -\u003e R) -\u003e T\n```\n##### `orderBy` / `orderByDescending` - create a sequence sorted by given key \n```swift\norderBy\u003cK: Comparable\u003e(key: T -\u003e K) -\u003e SinqOrderedSequence\u003cT\u003e\norderByDescending\u003cK: Comparable\u003e(key: T -\u003e K) -\u003e SinqOrderedSequence\u003cT\u003e\n```\n##### `reverse` - create a sequence with reverse order\n```swift\nreverse() -\u003e SinqSequence\u003cT\u003e\n```    \n##### `select` / `map` - create a sequence with results of applying given function\n```swift\nselect\u003cV\u003e(selector: T -\u003e V) -\u003e SinqSequence\u003cV\u003e\nselect\u003cV\u003e(selector: (T, Int) -\u003e V) -\u003e SinqSequence\u003cV\u003e\n```\n##### `selectMany` - create a sequence by concatenating function results for each element\n```swift\nselectMany\u003cS: Sequence\u003e(selector: T -\u003e S) -\u003e SinqSequence\u003cS.E\u003e\nselectMany\u003cS: Sequence\u003e(selector: (T, Int) -\u003e S) -\u003e SinqSequence\u003cS.E\u003e\nselectMany\u003cS: Sequence, R\u003e(selector: T -\u003e S, result: S.E -\u003e R) -\u003e SinqSequence\u003cR\u003e\nselectMany\u003cS: Sequence, R\u003e(selector: (T, Int) -\u003e S, result: S.E -\u003e R) -\u003e SinqSequence\u003cR\u003e\n```\n##### `single` - return the only element in a sequence containing exactly one element\n```swift\nsingle() -\u003e T\nsingleOrNil() -\u003e T?\nsingleOrDefault(defaultElement: T) -\u003e T\nsingle(predicate: T -\u003e Bool) -\u003e T\nsingleOrNil(predicate: T -\u003e Bool) -\u003e T?\nsingleOrDefault(defaultElement: T, predicate: T -\u003e Bool) -\u003e T\n```\n\n##### `skip` - create a sequence skipping (given number of elements | while predicate holds )\n```swift\nskip(count: Int) -\u003e SinqSequence\u003cT\u003e\nskipWhile(predicate: T -\u003e Bool) -\u003e SinqSequence\u003cT\u003e\n```\n##### `take` - create a sequence by taking (given number of elements | while predicate holds )\n```swift\ntake(count: Int) -\u003e SinqSequence\u003cT\u003e\ntakeWhile(predicate: T -\u003e Bool) -\u003e SinqSequence\u003cT\u003e\n```\n##### `thenBy` / `thenByDescending` - create a sequence by additionally sorting on given key\n```swift\nthenBy\u003cK: Comparable\u003e(key: T -\u003e K) -\u003e SinqOrderedSequence\u003cT\u003e\nthenByDescending\u003cK: Comparable\u003e(key: T -\u003e K) -\u003e SinqOrderedSequence\u003cT\u003e\n```\n##### `toArray` - create an array from the sequence\n```swift\ntoArray() -\u003e T[]\n```\n##### `toDictionary` / `toLookupDictionary` - create a dictionary from the sequence\n```swift\ntoDictionary\u003cK: Hashable, V\u003e(keyValue: T -\u003e (K, V)) -\u003e Dictionary\u003cK, V\u003e\ntoDictionary\u003cK: Hashable, V\u003e(key: T -\u003e K, value: T -\u003e V) -\u003e Dictionary\u003cK, V\u003e\ntoDictionary\u003cK: Hashable\u003e(key: T -\u003e K) -\u003e Dictionary\u003cK, T\u003e\n```\n##### `union` - create a sequence with unique elements from either of the sequences\n```swift\nunion\u003cS: Sequence\u003e(sequence: S, equality: (T, T) -\u003e Bool) -\u003e SinqSequence\u003cT\u003e\nunion\u003cS: Sequence, K: Hashable\u003e(sequence: S, key: T -\u003e K) -\u003e SinqSequence\u003cT\u003e\n```\n##### `whereTrue` / `filter` - create a sequence only with elements satisfying a predicate\n```swift\nwhereTrue(predicate: T -\u003e Bool) -\u003e SinqSequence\u003cT\u003e\n```\n##### `zip` - create a sequence by combining pairs of elements from two sequences\n```swift\nzip\u003cS: Sequence, R\u003e(sequence: S, result: (T, S.E) -\u003e R) -\u003e SinqSequence\u003cR\u003e\n```\n\n## Troubleshooting\n\nDue to bug in `swift` it *sometimes* happens that `swift` compiler and/or `SourceKitService` loop indefinitely while solving type constraints during compilation or indexing. If this happens, to help them solve the constraints, one might have to divide work for them into smaller pieces. For example this would cause inifinite loop:\n```swift\nfunc testAll() {\n  XCTAssertTrue(sinq([11, 12, 15, 10]).all{ $0 \u003e= 10 })\n  XCTAssertFalse(sinq([11, 12, 15, 10]).all{ $0 \u003e 10 })\n}\n```\nWhile this does not:\n```swift\nfunc testAll() {\n  let seq = sinq([11, 12, 15, 10])\n  XCTAssertTrue(seq.all{ $0 \u003e= 10 })\n  XCTAssertFalse(seq.all{ $0 \u003c 13 })\n}\n```\nIn this case it seems o be connected to `@auto_closure` arguments of `XCTAssert*`...\n\nIn case it happens for you, try to divide the statements like this or be more explicit in code about types and not depend as much on type inference.\n\n---\n¹ - this statement might become less true in the future, e.g. in Beta 4 Apple introduced `lazy()` which is similar to subset of `sinq()` in that it adds lazy chainable `.map` `.filter` `.reverse` `.array` and subscripting.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslazyk%2FSINQ","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslazyk%2FSINQ","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslazyk%2FSINQ/lists"}