{"id":13396619,"url":"https://github.com/oisdk/SwiftSequence","last_synced_at":"2025-03-13T23:31:38.414Z","repository":{"id":34298028,"uuid":"38200790","full_name":"oisdk/SwiftSequence","owner":"oisdk","description":"A μframework of extensions for SequenceType in Swift 2.0, inspired by Python's itertools, Haskell's standard library, and other things.","archived":false,"fork":false,"pushed_at":"2016-10-22T22:18:02.000Z","size":2675,"stargazers_count":375,"open_issues_count":1,"forks_count":16,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-07-31T18:17:45.802Z","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/oisdk.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2015-06-28T14:00:19.000Z","updated_at":"2024-04-27T14:07:49.000Z","dependencies_parsed_at":"2022-09-03T01:06:34.994Z","dependency_job_id":null,"html_url":"https://github.com/oisdk/SwiftSequence","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oisdk%2FSwiftSequence","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oisdk%2FSwiftSequence/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oisdk%2FSwiftSequence/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oisdk%2FSwiftSequence/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oisdk","download_url":"https://codeload.github.com/oisdk/SwiftSequence/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243500127,"owners_count":20300750,"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","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":"2024-07-30T18:00:58.210Z","updated_at":"2025-03-13T23:31:38.100Z","avatar_url":"https://github.com/oisdk.png","language":"Swift","readme":"[![Build Status](https://travis-ci.org/oisdk/SwiftSequence.svg?branch=master)](https://travis-ci.org/oisdk/SwiftSequence) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n\n# SwiftSequence #\n\nFull reference [here.](http://oisdk.github.io/SwiftSequence/index.html)\n\n(If you're looking for data structures in Swift, those have been moved to [here](https://github.com/oisdk/SwiftDataStructures))\n\nSwiftSequence is a lightweight framework of extensions to `SequenceType`. It has no requirements beyond the Swift standard library. Every function and method has both a strict and a lazy version, unless otherwise specified.\n\nTo make an eager sequence lazy, the `lazy` property can be used:\n\n```swift\n[1, 2, 3].lazy.hop(2)\n\n// 1, 3\n\n\n```\n## Contributing ##\n\nContributions welcome! Anything at all, as long as it's related to sequences, Linux-compatible, and has a test or two.\n\n\n## Contents ##\n\n  - [ScanReduce] (#scanreduce)\n  - [TakeDrop] (#takedrop)\n  - [Hopping and Slicing] (#hopping-and-slicing)\n  - [Interpose] (#interpose)\n  - [Combinations] (#combinations)\n  - [Permutations] (#permutations)\n  - [Cycle] (#cycle)\n  - [Categorise] (#categorise)\n  - [ChunkWindowSplit] (#chunkwindowsplit)\n  - [Enumerate] (#enumerate)\n  - [Finding] (#finding)\n  - [NestedSequences] (#nestedsequences)\n  - [Zip] (#zip)\n\n## ScanReduce ##\n\n### Reduce ###\n\n```swift\nfunc reduce\n    (@noescape combine: (accumulator: Generator.Element, element: Generator.Element) throws -\u003e Generator.Element)\n    rethrows -\u003e Generator.Element?\n```\n\nThis function works the same as the standard library reduce, except it takes the initial value to be the first element of `self`. It returns an optional, which is `nil` if `self` is empty.\n\n```swift\n[1, 2, 3, 4].reduce(+) == 10\n```\n\n### Scan ###\nReturns an array of the intermediate results of calling `combine` on successive elements of self and an accumulator: \n\n```swift\n[1, 2, 3].scan(0, combine: +)\n \n[1, 3, 6]\n```\n\nThe last element of this array will be equal to the result of calling `reduce` with the same arguments.\n\nThere is also, like reduce, a version that takes the first element of the sequence to be `initial`:\n\n```swift\n[1, 2, 3, 4, 5].scan(+)\n\n[3, 6, 10, 15]\n```\n\nThis also is evaluated lazily if the sequence it is called on is lazy.\n\n## TakeDrop ##\n\n### prefixWhile ###\n\nThis function returns all of the elements of `self` up until an element returns false for `predicate`:\n\n```swift\n[1, 2, 3, 4, 5, 2].prefixWhile { $0 \u003c 4 }\n\n[1, 2, 3]\n```\n\nNote that it's not the same as filter: if any elements return true for the predicate *after* the first element that returns false, they're still not returned.\n\n### dropWhile ###\n\nSimilar in behaviour to `prefixWhile`, this function drops the first elements of `self` that return true for a predicate:\n\n```swift\nlazy([1, 2, 3, 4, 5, 2]).dropWhile { $0 \u003c 4 }\n\n4, 5, 2\n```\n\n### breakAt ###\n\nReturns a tuple, the first element being the prefix of `self` of maximum length `n`, the second being the remaining elements of `self`.\n\n```swift\n[1, 2, 3, 4].breakAt(3) == ([1, 2, 3], [4])\n```\n\nThis also has a version which takes a predicate, which returns a tuple where the first element is the prefix of `self` up until the first element that returns `true` for `isBreak`.\n\n## Hopping and Slicing ##\n\nThis allows subscripting of several `CollectionType`s in a way similar to Python's slicing. For instance, you can slice in an open-ended way:\n\n```swift\nlet array = [0, 1, 2, 3, 4, 5, 6]\narray[3...] == [3, 4, 5, 6]\narray[...4] == [0, 1, 2, 3, 4]\narray[..\u003c4] == [0, 1, 2, 3]\n```\n\nYou can also mutate via slices:\n\n```swift\nvar array = [0, 1, 2, 3, 4, 5, 6]\narray[...3] = [10, 11, 12, 13]\narray == [10, 11, 12, 13, 4, 5, 6]\n```\n\nOr, you can hop over elements in the array:\n\n```swift\nlet array = [0, 1, 2, 3, 4, 5, 6]\narray[2..., by: 2] // [2, 4, 6]\n```\n\n\n## Interpose ##\n\nThese functions allow lazy and eager insertion of elements into sequences at regular intervals.\n\n### Interpose ###\n\nThis function returns `self`, with `element` inserted between every element:\n\n```swift\n[1, 2, 3].interpose(10)\n\n[1, 10, 2, 10, 3]\n```\n\nThe intervals at which to insert `element` can be specified:\n\n```swift\n[1, 2, 3, 4, 5].interpose(10, n: 2)\n\n[1, 2, 10, 3, 4, 10, 5]\n```\n\nMore than one element can be interposed:\n\n```swift\n[1, 2, 3].interpose([10, 20])\n\n[1, 10, 20, 2, 10, 20, 3]\n```\n\nAnd, again, the interval can be specified:\n\n```swift\n[1, 2, 3, 4, 5].interpose([10, 20], n: 2)\n\n[1, 2, 10, 20, 3, 4, 10, 20, 5]\n```\n\n### interdig ###\n\nThis function allows you to combine two sequences by alternately selecting elements from each:\n\n```swift\ninterdig([1, 2, 3], [10, 20, 30])\n\n[1, 10, 2, 20, 3, 30]\n```\n\nThe length of the interdigitations can be specified:\n\n```swift\ninterdig([1, 2, 3, 4, 5], [10, 20, 30, 40, 50, 60], s0Len: 2, s1Len: 3)\n\n[1, 2, 10, 20, 30, 3, 4, 40, 50, 60, 5]\n```\n\n## Combinations ##\n\nThese functions return combinations with or without repetition, lazily or eagerly. The lazy version of these function doesn't maintain laziness of the underlying sequence, but they produce combinations on-demand, with neither future nor past combinations stored in memory, e.g:\n\n```swift\n\nlet lazySequence = [1, 2, 3].lazy\n\nlet lazyCombos = lazySequence.lazyCombinations(2)\n\n// Here, lazySequence was evaluated, but no combinations have yet been evaluated.\n\nvar g = lazyCombos.generate()\n\ng.next() == [1, 2]\n\n// Here, only one combination has been evaluated, and only that combination is stored in memory\n\ng.next() == [1, 3]\n\n// Here, two combinations have been evaluated, but no extra combinations have been stored in memory.\n\n```\n\n### Combinations ###\n\nReturns combinations without repetitions of self of length `n`\n\nCombinations are returned in lexicographical order, according to the order of `self`\n\n```swift\n[1, 2, 3].combinations(2)\n\n[1, 2], [1, 3], [2, 3]\n```\n\nTo have combinations generate lazily and on-demand, use `lazyCombinations()`.\n\nExample Recipe:\n\n```swift\nextension CollectionType {\n  func powerSet() -\u003e FlatMapSeq\u003cLazyForwardCollection\u003cSelf\u003e, ComboSeq\u003c[Self.Generator.Element]\u003e\u003e {\n    var i = 0\n    return lazy(self).flatMap { _ in self.lazyCombinations(++i) }\n  }\n}\n\n[1, 2, 3]       // [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]\n  .powerSet()\n```\n\n### Combinations with Repetition ###\n\nReturns combinations with repetition of self of length `n`.\n\nCombinations are returned in lexicographical order, according to the order of `self`.\n\n```swift\n[1, 2, 3].combinationsWithRep(2)\n\n[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3]\n```\n\nTo have combinations generate lazily and on-demand, use `lazyCombinationsWithRep()`.\n\n## Permutations ##\n\n### Lexicographical Permutations\n\nThese functions return `self`, permuted, in lexicographical order. If `self` is not the first permutation, lexicographically, not all permutations will be returned. (to ensure all permutations are returned, `sort()` can be used). This function can operate on a collection of `Comparable` elements, or, is the closure `isOrderedBefore` is provided, it can operate on any collection. In terms of laziness, it behaves the same as the combination functions: forcing the evaluation of the underlying collection, but capable of lazily producing each new permutation. To access the lazy version, use the versions of these functions with the `lazy` prefix. (e.g., `lexPermutations()` becomes `lazyLexPermutations()`)\n```swift\n[1, 2, 3].lexPermutations()\n\n[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]\n```\n```swift\n[3, 2, 1].lexPermutations()\n\n[[3, 2, 1]]\n```\n\n```swift\n[1, 2, 3].lexPermutations(\u003c)\n\n[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]\n```\n```swift\n[1, 2, 3].lexPermutations(\u003e)\n\n[[1, 2, 3]]\n```\n\n### Permutations ###\n\nThese functions use the same algorithm as the lexicographical permutations, but the indices of self are permuted. (Indices aren't returned: they're just used for the permutation)\n\n```swift\n[1, 2, 3].permutations()\n\n[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]\n```\n```swift\nlazy([3, 2, 1]).lazyPermutations()\n\n[3, 2, 1], [3, 1, 2], [2, 3, 1], [2, 1, 3], [1, 3, 2], [1, 2, 3]\n```\n\n\n## Cycle ##\n\nThese functions return a cycle of self. The number of cycles can be specified, if not, `self` is cycled infinitely.\n\nWhen called on a `LazySequenceType`, the sequence returned is lazy, otherwise, it's eager. (the infinite cycle is always lazy, however)\n\n```swift\n[1, 2, 3].cycle(2)\n\n[1, 2, 3, 1, 2, 3]\n```\n```swift\n[1, 2, 3].cycle()\n\n1, 2, 3, 1, 2, 3, 1...\n```\n\n## Categorise ##\n\nThese functions can be used to group elements of a sequence on certain conditions.\n\n### categorise ###\n\n```swift\nfunc categorise\u003cU : Hashable\u003e(keyFunc: Generator.Element -\u003e U) -\u003e [U:[Generator.Element]] \n```\n\nThis categorises all elements of self into a dictionary, with the keys of that dictionary given by the `keyFunc`.\n\n```swift\n[1, 2, 3, 4, 5, 6].categorise { $0 % 2 }\n\n\n[\n  0: [2, 4, 6],\n  1: [1, 3, 5]\n]\n\n```\n\n(this function has no lazy version)\n\n### Frequencies ###\n\nThis returns a dictionary where the keys are the elements of self, and the values are their respective frequencies:\n\n```swift\n\n[1, 1, 1, 2, 2, 3].freqs()\n\n[\n  1: 3,\n  2: 2,\n  3: 1\n]\n\n```\n\n(this function has no lazy version)\n\n### Uniques ###\n\nReturns `self` with duplicates removed:\n\n```swift\n[1, 2, 3, 2, 2, 4, 1, 2, 5, 6].uniques()\n\n[1, 2, 3, 4, 5, 6]\n```\n\n### Grouping ###\n\nSince `categorise()` and `freqs()` can't have lazy versions, these grouping functions give similar behaviour. Instead of categorising based on the whole sequence, they categories based on *adjacent* values.\n\nThis groups adjacent equal values:\n\n``` swift\nlazy([1, 2, 2, 3, 1, 1, 3, 4, 2]).group()\n\n[1], [2, 2], [3], [1, 1], [3], [4], [2]\n```\nThis groups adjacent equal values according to a closure:\n\n```swift\nlazy([1, 3, 5, 20, 22, 18, 6, 7]).group { abs($0 - $1) \u003c 5 }\n\n[1, 3, 5], [20, 22, 18], [6, 7]\n```\n\nThis groups adjacent values that return the same from `keyFunc`:\n\n```swift\nlazy([1, 3, 5, 2, 4, 6, 6, 7, 1, 1]).groupBy { $0 % 2 }\n\n[1, 3, 5], [2, 4, 6, 6], [7, 1, 1]\n```\n\n## ChunkWindowSplit ##\n\nThese functions divide up a sequence.\n\n### Chunk ###\n\nThis function returns `self`, broken up into non-overlapping arrays of length `n`:\n\n```swift\n[1, 2, 3, 4, 5].chunk(2)\n\n[[1, 2], [3, 4], [5]]\n```\n\n### Window ###\n\nThis function returns `self`, broken up into overlapping arrays of length `n`:\n\n```swift\n[1, 2, 3, 4, 5].window(3)\n\n[[1, 2, 3], [2, 3, 4], [3, 4, 5]]\n```\n\n## Enumerate ##\n\nThis just adds the function `specEnumerate()` which is the same as the standard library `enumerate()`, except that the indices it returns are specific to the base, rater than just `Int`s. So, for instance, this:\n\n```swift\n\"hello\".characters.specEnumerate()\n```\n\nWould return a sequence of `(String.Index, Character)` (rather than `(Int, Character)`, which is what the standard library `enumerate()` returns). There is no eager version of this function (as there is no eager `enumerate()`)\n\n## Finding ##\n\nThe methods here are intended to replace patterns like this:\n\n```swift\n[1, 2, 3, 4, 5, 6].filter { n in n \u003e 4 }.first\n[1, 2, 3, 4, 5, 6].filter { n in n % 2 == 0 }.count\n```\n\nWhere filter is used in a chain with one of the `CollectionType` properties, like `first` or `count`.\n\nThese chains are needlessly inefficient: they allocate and fill an array unnecessarily. Even if the `lazy` property is used, the actual operations are unexpected. The code below, for instance:\n\n```swift\nvar i = 0\n\n[1, 2, 3, 4, 5, 6]\n  .lazy\n  .filter { n in\n    print(++i)\n    return n \u003e 4\n}.first\n```\nWill print one through ten.\n\n`first`, `last`, and `count` methods are all provided, which take predicates, as well as `indicesOf` and `lastIndexOf`.\n\nA `partition` method is also available, which splits `self` into a tuple of arrays which satisfy and do not satisfy `predicate`, respectively.\n\n\n## NestedSequences ##\n\n### Transpose ###\n\nAllows both lazy and eager transposition. When lazily transposing, each row is evaluated eagerly, but only that row:\n\n```swift\nlet transposed = lazy([\n  [1, 2, 3],\n  [1, 2, 3],\n  [1, 2, 3]\n]).transpose()\n\nvar g = transposed.generate()\n\ng.next() == [1, 1, 1]\n\n// Each row is an eager array, but only that row is evaluated.\n\ng.next() == [2, 2, 2]\n\n// It's safe to use with single-pass sequences, also, as each sequence is only evaluated once.\n\n```\n\n### Product ###\n\nBoth lazy and eager Cartesian Products.\n\n```swift\nproduct([1, 2], [3, 4])\n\n[[1, 3], [1, 4], [2, 3], [2, 4]]\n\nlazyProduct([1, 2], [3, 4])\n\n[1, 3], [1, 4], [2, 3], [2, 4]\n```\n\n## Zip ##\n\nThese functions allow you to zip two sequences of different lengths together, and to specify the padding for the shorter sequence. If unspecified, the padding is `nil`. There is no eager version of this function (there is no eager standard library zip)\n\n\n```swift\nzipWithPadding([1, 2, 3], [1, 2], pad0: 100, pad1: 900)\n\n(1, 1), (2, 2), (3, 900)\n```\n\n```swift\nzipWithPadding([1, 2, 3], [1, 2])\n\n(1?, 1?), (2?, 2?), (3?, nil)\n```\n","funding_links":[],"categories":["Swift","Extensions","Libraries","Libs"],"sub_categories":["[Swift](https://developer.apple.com/swift)","Utility"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foisdk%2FSwiftSequence","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foisdk%2FSwiftSequence","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foisdk%2FSwiftSequence/lists"}