{"id":16431476,"url":"https://github.com/dcastro/sequences","last_synced_at":"2025-08-02T01:10:44.285Z","repository":{"id":16065700,"uuid":"18810016","full_name":"dcastro/Sequences","owner":"dcastro","description":"A port of Scala's Stream[+A] to C#.","archived":false,"fork":false,"pushed_at":"2022-10-07T01:07:32.000Z","size":1345,"stargazers_count":13,"open_issues_count":1,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-19T23:26:52.921Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://dcastro.github.io/Sequences","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dcastro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-04-15T17:57:05.000Z","updated_at":"2022-10-11T17:09:35.000Z","dependencies_parsed_at":"2023-01-11T20:24:27.512Z","dependency_job_id":null,"html_url":"https://github.com/dcastro/Sequences","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/dcastro/Sequences","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcastro%2FSequences","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcastro%2FSequences/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcastro%2FSequences/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcastro%2FSequences/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dcastro","download_url":"https://codeload.github.com/dcastro/Sequences/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcastro%2FSequences/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268322414,"owners_count":24231819,"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-08-01T02:00:08.611Z","response_time":67,"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":"2024-10-11T08:30:25.494Z","updated_at":"2025-08-02T01:10:44.229Z","avatar_url":"https://github.com/dcastro.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sequences\n\nSequences is a port of Scala's [`Stream[+A]`][3] to C#.\n\nA `Sequence\u003cT\u003e` is an immutable lazy list whose elements are only evaluated when they are needed. A sequence is composed by a *head* (the first element) and a lazily-evaluated *tail* (the remaining elements).\n\nThe fact that the tail is lazily-evaluated, makes it easy to represent infinite series or sets. For example, here's how to represent the set of all natural numbers.\n\n\n```cs\npublic ISequence\u003cint\u003e Naturals(int start)\n{\n    return new Sequence\u003cint\u003e( head: start,\n                              tail: () =\u003e Naturals(start + 1));\n}\n\nvar naturals = Naturals(1);\n\n//take the first 5 natural numbers\nnaturals.Take(5).ForEach(Console.Write); //prints 12345\n```\n\nOr, even simpler:\n\n```cs\nvar naturals = Sequence.From(1);\n```\n\nSequences also features memoization, i.e., the sequence stores previously computed values to avoid re-evaluation.\n\n```cs\n//start with number 1, and then keep adding 2 to the previous number\nvar odds = Sequence.Iterate(1, odd =\u003e\n    {\n        Console.WriteLine(\"Adding \" + odd + \" + 2\");\n        return odd + 2;\n    });\n\nodds.Take(3).ForEach(Console.WriteLine);\nodds.Take(5).ForEach(Console.WriteLine);\n\n//prints\n//1\n//Adding 1 + 2\n//3\n//Adding 3 + 2\n//5\n\n//and then\n//1\n//3\n//5\n//Adding 5 + 2\n//7\n//Adding 7 + 2\n//9\n```\n\nYou can iterate through an infinite sequence for as long as you want. As long as you don't hold onto its head, each sequence will be elected for garbage collection as soon as you move to the next value. This prevents an infinite sequence from occupying a large and growing ammount of memory.\n\n```cs\nforeach (var odd in Sequence.Iterate(1, odd =\u003e odd + 2))\n{\n    //when you move to Sequence(11, ?),\n    //the previous Sequence(9, ?) is elected for collection.\n}\n```\n\n## Examples\n\nThe above natural numbers example is very simple. But Sequences allow for so much more. So let's explore some more complex examples.\n\n#### Fibonacci sequence\n\nThe Fibonacci sequence is a famous series in mathematics, where each fibonacci number is defined as the sum of the two previous fibonacci numbers, i.e. `F(n) = F(n-1) + F(n-2)`, with seed values `F(0) = 0` and `F(1) = 1`.\n\nIn scala, the fibonacci sequence is commonly expressed as follows:\n\n```scala\nval fibs: Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map { n =\u003e n._1 + n._2 }\n```\n\nIn C#, the syntax is a little more verbose, but still readable:\n\n```cs\nFunc\u003cTuple\u003cint, int\u003e, int\u003e sum = pair =\u003e pair.Item1 + pair.Item2;\n\nISequence\u003cint\u003e fibs = null;\n\nfibs = Sequence.With(0, 1)               //start with (0, 1, ?)\n               .Concat(() =\u003e             //and then\n                   fibs.Zip(fibs.Tail)   //zip the sequence with its tail (i.e., (0,1), (1,1), (1,2), (2,3), (3, 5))\n                       .Select(sum));    //select the sum of each pair (i.e., 1, 2, 3, 5, 8)\n```\n\nThe code above creates more objects than needed. The following implementation shows a more efficient way of representing the fibonacci sequence:\n\n```cs\nusing System.Numerics;\n\n//current and next are any two consecutive fibonacci numbers.\nISequence\u003cBigInteger\u003e Fibs(BigInteger current, BigInteger next)\n{\n    return new Sequence\u003cBigInteger\u003e(current, () =\u003e Fibs(next, current + next));\n}\n\nvar fibs = Fibs(0, 1);\n\n//prints 0 1 1 2 3 5 8 13 21 34\nfibs.Take(10).ForEach(Console.WriteLine);\n```\n\n#### Prime numbers\n\nOne way to find every prime number in a given range is to use the [Sieve of Eratosthenes][4].\nTo find the prime numbers up to 100, a slight variation of the sieve goes like this:\n\n1. Start with a list representing the range [2, 100].\n2. Let *p* be the head of the list.\n3. Take *p* as the next prime number, and remove every multiple of *p* from the list.\n4. If the list is empty:\n  * stop;\n  * otherwise, repeat from step 2.\n\nHere's a way of implementing the sieve as a sequence.\n\n```cs\nvar range = Sequence.Range(2, 101);\nvar primes = PrimesWithin(range);\n\n//prints: 2 3 5 7 11\nConsole.WriteLine(primes.Take(5).MkString(\" \"));\n\npublic ISequence\u003cint\u003e PrimesWithin(ISequence\u003cint\u003e range)\n{\n    if (range.IsEmpty)\n        return Sequence.Empty\u003cint\u003e();\n\n    //take the next prime number\n    var p = range.Head;\n\n    //skip p, and remove further multiples of p\n    var filtered = range.Tail.Where(num =\u003e num % p != 0).Force();\n\n    return new Sequence\u003cint\u003e(p, () =\u003e PrimesWithin(filtered));\n}\n```\n\n#### Pascal's Triangle\n\nEveryone knows the famous [Pascal's Triangle][6].\n\n![Pascal's Triangle][pascal]\n\nThe triangle starts with a 1 at the top. In every other row, each number is the sum of the two directly above it.\n\nThere are all sorts of ways of representing Pascal's triangle using sequences, but here's an interesting one:\n\n```cs\nFunc\u003cTuple\u003cint, int\u003e, int\u003e sum = pair =\u003e pair.Item1 + pair.Item2;\n\nFunc\u003cISequence\u003cint\u003e, ISequence\u003cint\u003e\u003e rowFactory =\n    row =\u003e row.Append(0)                //shift row to the left\n              .Zip(row.Prepend(0))      //shift row to the right, and zip both shifted rows\n              .Select(sum);             //sum the two shifted rows\n\nvar triangle = Sequence.Iterate(\n                            start: Sequence.With(1),\n                            func: rowFactory);\n```\n\nYou start with row (1). From then on, every row is computed by shifting the row to the right, shifting the row to the left, zipping both shifted rows together and producing the sum of each tuple. For example, given the row (1, 3, 3, 1):\n\n```\n0 1 3 3 1       //shift right\n1 3 3 1 0       //shift left\n↓ ↓ ↓ ↓ ↓\n1 4 6 4 1\n```\n\nFor more examples, refer to the [functional tests project][1].\n\n## Limitations\n\nDue to a limitation in [generic type constraints][5] as of C# 5.0, sequences are *not* covariant, as opposed to Scala's `Stream[+A]`.\n\nTake the signature of `copyToBuffer` in Scala as an example:\n\n```scala\ncopyToBuffer[B \u003e: A](dest: Buffer[B]): Unit\n```\n\nThe constraint `B \u003e: A` (read *A derives from B*) cannot be expressed in C# (even though the opposite can be expressed as `where B : A` or *B derives from A*) unless `A` is also one of *copyToBuffer*'s type parameters - which it isn't.\n\n## Documentation\nDocumentation is available at [dcastro.github.io/Sequences][2].\n\n## NuGet\nTo install [Sequences][7], run the following command in the Package Manager Console\n\n```\nPM\u003e Install-Package Sequences\n```\n\n[1]: https://github.com/dcastro/Sequences/tree/master/tests/Sequences.Tests.Functional\n[2]: http://diogocastro.com/Sequences\n[3]: http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Stream\n[4]: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes\n[5]: http://msdn.microsoft.com/en-gb/library/d5x73970.aspx\n[6]: http://en.wikipedia.org/wiki/Pascal's_triangle\n[7]: https://www.nuget.org/packages/Sequences/\n[pascal]: https://raw.githubusercontent.com/dcastro/Sequences/master/docs/Sequence.Docs/Media/pascals-triangle.png\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdcastro%2Fsequences","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdcastro%2Fsequences","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdcastro%2Fsequences/lists"}