├── global.json ├── MoreLinq ├── key.snk ├── tt.sh ├── tt.cmd ├── OrderByDirection.cs ├── ReverseComparer.cs ├── Consume.cs ├── Experimental │ └── ExperimentalEnumerable.cs ├── AssemblyInfo.cs ├── Evaluate.cs ├── GenerateByIndex.cs ├── MoreEnumerable.cs ├── SkipLast.cs ├── Prepend.cs ├── TakeEvery.cs ├── Acquire.cs ├── ListLike.cs ├── Pipe.cs ├── Generate.cs ├── NestedLoops.cs ├── Append.cs ├── ForEach.cs ├── TakeLast.cs ├── Index.cs ├── Exclude.cs ├── Repeat.cs ├── ToHashSet.cs ├── Choose.cs ├── SequenceException.cs ├── ToDelimitedString.cs ├── Fold.g.tt ├── TagFirstLast.cs ├── Pairwise.cs ├── Slice.cs ├── Shuffle.cs └── ZipImpl.cs ├── .editorconfig ├── pack.sh ├── MoreLinq.Test ├── Program.cs ├── Combinatorics.cs ├── Comparer.cs ├── TestException.cs ├── BreakingReadOnlyList.cs ├── KeyValuePair.cs ├── AssertThrowsArgument.cs ├── BreakingList.cs ├── Scope.cs ├── ConsumeTest.cs ├── EqualityComparer.cs ├── BreakingReadOnlyCollection.cs ├── BreakingSequence.cs ├── CurrentThreadCultureScope.cs ├── ForEachTest.cs ├── BreakingAction.cs ├── PairwiseTest.cs ├── BreakingFunc.cs ├── BreakingCollection.cs ├── ToDelimitedStringTest.cs ├── SampleData.cs ├── SkipLastTest.cs ├── WatchableEnumerator.cs ├── EvaluateTest.cs ├── PipeTest.cs ├── IndexTest.cs ├── TakeUntilTest.cs ├── SkipUntilTest.cs ├── FillBackwardTest.cs ├── GenerateTest.cs ├── DistinctByTest.cs ├── TakeEveryTest.cs ├── SplitTest.cs ├── TagFirstLastTest.cs ├── PreScanTest.cs ├── AssertTest.cs ├── ShuffleTest.cs ├── ExactlyTest.cs ├── PadTest.cs ├── BacksertTest.cs ├── CountBetweenTest.cs ├── ExceptByTest.cs ├── AcquireTest.cs ├── TakeLastTest.cs ├── WindowLeftTest.cs ├── ScanTest.cs ├── WindowRightTest.cs ├── AtMostTest.cs ├── ChooseTest.cs ├── FallbackIfEmptyTest.cs ├── TestingSequence.cs ├── ToDictionaryTest.cs ├── BatchTest.cs ├── InsertTest.cs ├── PrependTest.cs ├── AppendTest.cs └── UnfoldTest.cs ├── pack.cmd ├── .gitattributes ├── bld ├── ExtensionsGenerator │ └── MoreLinq.ExtensionsGenerator.csproj └── Copyright.props ├── test.sh ├── test.cmd ├── .gitignore ├── msbuild.cmd ├── .travis.yml ├── appveyor.yml └── MoreLinq.sln /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "2.1.500" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /MoreLinq/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fsateler/MoreLINQ/HEAD/MoreLinq/key.snk -------------------------------------------------------------------------------- /MoreLinq/tt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | cd "$(dirname "$0")" 4 | find . -name "*.tt" -print0 | xargs -0 -t -L 1 sh -c '(dotnet tt "$0" || exit 255)' 5 | -------------------------------------------------------------------------------- /MoreLinq/tt.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | pushd "%~dp0" 3 | for /f "tokens=*" %%f in ('dir /s /b *.tt') do ( 4 | echo>&2 dotnet tt "%%f" 5 | dotnet tt "%%f" || goto :end 6 | ) 7 | :end 8 | popd 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | insert_final_newline = true 5 | trim_trailing_whitespace = true 6 | 7 | [*.xml] 8 | indent_style = space 9 | 10 | [*.{cs,tt}] 11 | charset = utf-8 12 | indent_style = space 13 | indent_size = 4 14 | -------------------------------------------------------------------------------- /pack.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | cd "$(dirname "$0")" 4 | VERSION_SUFFIX= 5 | if [ ! -z "$1" ]; then VERSION_SUFFIX="--version-suffix $1"; fi 6 | ./build.sh 7 | if [ ! -d dist ]; then mkdir dist; fi 8 | ./msbuild.sh /v:m /t:Pack \ 9 | /p:Configuration=Release \ 10 | $VERSION_SUFFIX \ 11 | MoreLinq/MoreLinq.csproj 12 | -------------------------------------------------------------------------------- /MoreLinq.Test/Program.cs: -------------------------------------------------------------------------------- 1 | namespace MoreLinq.Test 2 | { 3 | using System; 4 | using System.Reflection; 5 | using NUnit.Common; 6 | using NUnitLite; 7 | 8 | static class Program 9 | { 10 | static int Main(string[] args) => 11 | new AutoRun(typeof(Program).GetTypeInfo().Assembly) 12 | .Execute(args, new ExtendedTextWrapper(Console.Out), Console.In); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /pack.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | pushd "%~dp0" 3 | call :main %* 4 | popd 5 | goto :EOF 6 | 7 | :main 8 | setlocal 9 | if not exist dist md dist 10 | if not %errorlevel%==0 exit /b %errorlevel% 11 | set VERSION_SUFFIX= 12 | if not "%~1"=="" set VERSION_SUFFIX=/p:VersionSuffix=%1 13 | call build ^ 14 | && dotnet pack /p:Configuration=Release ^ 15 | %VERSION_SUFFIX% ^ 16 | MoreLinq\MoreLinq.csproj 17 | goto :EOF 18 | -------------------------------------------------------------------------------- /MoreLinq.Test/Combinatorics.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace MoreLinq.Test 3 | { 4 | static class Combinatorics 5 | { 6 | public static double Factorial(int n) 7 | { 8 | var fac = 1.0d; 9 | while (n > 0) 10 | fac *= n--; 11 | return fac; 12 | } 13 | 14 | public static double Binomial(int n, int k) => 15 | Factorial(n) / (Factorial(n - k) * Factorial(k)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | *.sh eol=lf 5 | 6 | # Custom for Visual Studio 7 | *.cs diff=csharp 8 | 9 | # Standard to msysgit 10 | *.doc diff=astextplain 11 | *.DOC diff=astextplain 12 | *.docx diff=astextplain 13 | *.DOCX diff=astextplain 14 | *.dot diff=astextplain 15 | *.DOT diff=astextplain 16 | *.pdf diff=astextplain 17 | *.PDF diff=astextplain 18 | *.rtf diff=astextplain 19 | *.RTF diff=astextplain 20 | -------------------------------------------------------------------------------- /bld/ExtensionsGenerator/MoreLinq.ExtensionsGenerator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | netcoreapp2.1 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | cd "$(dirname "$0")" 4 | ./build.sh 5 | for v in 1.0 2.0 2.1; do 6 | for c in Debug Release; do 7 | dotnet exec MoreLinq.Test/bin/$c/netcoreapp$v/MoreLinq.Test.dll 8 | done 9 | done 10 | if [[ -z `which mono 2>/dev/null` ]]; then 11 | echo>&2 NOTE! Mono does not appear to be installed so unit tests 12 | echo>&2 against the Mono runtime will be skipped. 13 | else 14 | mono MoreLinq.Test/bin/Debug/net451/MoreLinq.Test.exe 15 | mono MoreLinq.Test/bin/Release/net451/MoreLinq.Test.exe 16 | fi 17 | -------------------------------------------------------------------------------- /bld/Copyright.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | © 2008 Jonathan Skeet. 5 | Portions © 2009 Atif Aziz, Chris Ammerman, Konrad Rudolph. 6 | Portions © 2010 Johannes Rudolph, Leopold Bushkin. 7 | Portions © 2015 Felipe Sateler, “sholland”. 8 | Portions © 2016 Andreas Gullberg Larsen, Leandro F. Vieira (leandromoh). 9 | Portions © 2017 Jonas Nyrup (jnyrup). 10 | Portions © Microsoft. All rights reserved. 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /test.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | pushd "%~dp0" 3 | call :main %* 4 | popd 5 | goto :EOF 6 | 7 | :main 8 | setlocal 9 | call build ^ 10 | && call :test netcoreapp1.0 Debug ^ 11 | && call :test netcoreapp1.0 Release ^ 12 | && call :test netcoreapp2.0 Debug ^ 13 | && call :test netcoreapp2.0 Release ^ 14 | && call :test netcoreapp2.1 Debug ^ 15 | && call :test netcoreapp2.1 Release ^ 16 | && call :test net451 Debug ^ 17 | && call :test net451 Release 18 | goto :EOF 19 | 20 | :test 21 | setlocal 22 | echo Testing %1 (%2)... 23 | if %1==net451 ( 24 | MoreLinq.Test\bin\%2\net451\MoreLinq.Test.exe 25 | ) else ( 26 | dotnet exec MoreLinq.Test\bin\%2\%1\MoreLinq.Test.dll 27 | ) 28 | goto :EOF 29 | -------------------------------------------------------------------------------- /MoreLinq.Test/Comparer.cs: -------------------------------------------------------------------------------- 1 | namespace MoreLinq.Test 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | sealed class Comparer 7 | { 8 | /// 9 | /// Creates an given a 10 | /// . 11 | /// 12 | 13 | public static IComparer Create(Func compare) => 14 | new DelegatingComparer(compare); 15 | 16 | sealed class DelegatingComparer : IComparer 17 | { 18 | readonly Func _comparer; 19 | 20 | public DelegatingComparer(Func comparer) 21 | { 22 | _comparer = comparer ?? throw new ArgumentNullException(nameof(comparer)); 23 | } 24 | 25 | public int Compare(T x, T y) => _comparer(x, y); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### VisualStudio ### 2 | ## Ignore Visual Studio temporary files, build results, and 3 | ## files generated by popular Visual Studio add-ons. 4 | 5 | # User-specific files 6 | *.suo 7 | *.user 8 | *.userosscache 9 | *.sln.docstates 10 | 11 | # Build results 12 | [Dd]ebug/ 13 | [Dd]ebugPublic/ 14 | [Rr]elease/ 15 | [Rr]eleases/ 16 | x64/ 17 | x86/ 18 | build/ 19 | [Bb]in/ 20 | [Oo]bj/ 21 | 22 | # Visual Studio 2015 cache/options directory 23 | .vs/ 24 | 25 | # NUNIT 26 | *.VisualState.xml 27 | TestResult.xml 28 | 29 | # ReSharper 30 | _ReSharper*/ 31 | *.[Rr]e[Ss]harper 32 | *.DotSettings.user 33 | 34 | # CodeRush 35 | **/\.cr/ 36 | 37 | NuGet Packages 38 | *.nupkg 39 | # The packages folder can be ignored because of Package Restore 40 | **/packages/* 41 | # except build/, which is used as an MSBuild target. 42 | !**/packages/build/ 43 | 44 | docs/ 45 | 46 | .vscode/ 47 | *.lock.json 48 | tools/ 49 | 50 | # IntelliJ Platform excludes 51 | 52 | .idea/ 53 | 54 | -------------------------------------------------------------------------------- /MoreLinq.Test/TestException.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2012 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | /// 21 | /// Reserved for use within tests. 22 | /// 23 | 24 | sealed class TestException : System.Exception {} 25 | } 26 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingReadOnlyList.cs: -------------------------------------------------------------------------------- 1 | namespace MoreLinq.Test 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | /// 7 | /// This class implement but specifically prohibits enumeration using GetEnumerator(). 8 | /// It is provided to assist in testing extension methods that MUST NOT call the GetEnumerator() 9 | /// method of - either because they should be using the indexer or because they are 10 | /// expected to be lazily evaluated. 11 | /// 12 | 13 | sealed class BreakingReadOnlyList : BreakingReadOnlyCollection, IReadOnlyList 14 | { 15 | readonly IReadOnlyList _list; 16 | 17 | public BreakingReadOnlyList(params T[] values) : this ((IReadOnlyList) values) {} 18 | public BreakingReadOnlyList(IReadOnlyList list) : base (list) 19 | => _list = list; 20 | 21 | public T this[int index] => _list[index]; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /MoreLinq.Test/KeyValuePair.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | 22 | static class KeyValuePair 23 | { 24 | public static KeyValuePair Create(TKey key, TValue value) => 25 | new KeyValuePair(key, value); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /MoreLinq.Test/AssertThrowsArgument.cs: -------------------------------------------------------------------------------- 1 | namespace MoreLinq.Test 2 | { 3 | using System; 4 | using NUnit.Framework; 5 | 6 | sealed class AssertThrowsArgument 7 | { 8 | [Obsolete("This is redundant with the NullArgumentTest fixture.")] 9 | public static void NullException(string expectedParamName, TestDelegate code) 10 | { 11 | Exception(expectedParamName, code); 12 | } 13 | 14 | public static void Exception(string expectedParamName, TestDelegate code) 15 | { 16 | Exception(expectedParamName, code); 17 | } 18 | 19 | public static void OutOfRangeException(string expectedParamName, TestDelegate code) 20 | { 21 | Exception(expectedParamName, code); 22 | } 23 | 24 | static void Exception(string expectedParamName, TestDelegate code) where TActual : ArgumentException 25 | { 26 | var e = Assert.Throws(code); 27 | 28 | Assert.That(e.ParamName, Is.EqualTo(expectedParamName)); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingList.cs: -------------------------------------------------------------------------------- 1 | namespace MoreLinq.Test 2 | { 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | 7 | /// 8 | /// This class implement but specifically prohibits enumeration using GetEnumerator(). 9 | /// It is provided to assist in testing extension methods that MUST NOT call the GetEnumerator() 10 | /// method of - either because they should be using the indexer or because they are 11 | /// expected to be lazily evaluated. 12 | /// 13 | 14 | sealed class BreakingList : BreakingCollection, IList 15 | { 16 | public BreakingList() : this(new List()) {} 17 | public BreakingList(List list) : base(list) {} 18 | 19 | public int IndexOf(T item) => List.IndexOf(item); 20 | public void Insert(int index, T item) => throw new NotImplementedException(); 21 | public void RemoveAt(int index) => throw new NotImplementedException(); 22 | 23 | public T this[int index] 24 | { 25 | get => List[index]; 26 | set => throw new NotImplementedException(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /MoreLinq.Test/Scope.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | 22 | abstract class Scope : IDisposable 23 | { 24 | readonly T _old; 25 | 26 | protected Scope(T current) 27 | { 28 | _old = current; 29 | } 30 | 31 | public virtual void Dispose() 32 | { 33 | Restore(_old); 34 | } 35 | 36 | protected abstract void Restore(T old); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /MoreLinq.Test/ConsumeTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class ConsumeTest 24 | { 25 | [Test] 26 | public void ConsumeReallyConsumes() 27 | { 28 | var counter = 0; 29 | var sequence = Enumerable.Range(0, 10).Pipe(x => counter++); 30 | sequence.Consume(); 31 | Assert.AreEqual(10, counter); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /MoreLinq.Test/EqualityComparer.cs: -------------------------------------------------------------------------------- 1 | namespace MoreLinq.Test 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | static class EqualityComparer 7 | { 8 | /// 9 | /// Creates an given a 10 | /// . 11 | /// 12 | 13 | public static IEqualityComparer Create(Func comparer) => 14 | new DelegatingComparer(comparer); 15 | 16 | sealed class DelegatingComparer : IEqualityComparer 17 | { 18 | readonly Func _comparer; 19 | readonly Func _hasher; 20 | 21 | public DelegatingComparer(Func comparer) 22 | : this(comparer, x => x == null ? 0 : x.GetHashCode()) {} 23 | 24 | DelegatingComparer(Func comparer, Func hasher) 25 | { 26 | _comparer = comparer ?? throw new ArgumentNullException(nameof(comparer)); 27 | _hasher = hasher ?? throw new ArgumentNullException(nameof(hasher)); 28 | } 29 | 30 | public bool Equals(T x, T y) => _comparer(x, y); 31 | public int GetHashCode(T obj) => _hasher(obj); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /MoreLinq/OrderByDirection.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2010 Leopold Bushkin. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | /// 21 | /// Enumeration that defines values representing valid ordering directions for a sequence. 22 | /// 23 | 24 | public enum OrderByDirection 25 | { 26 | /// 27 | /// Elements are ordered by increasing value 28 | /// 29 | Ascending = 0, 30 | /// 31 | /// Elements are ordered by decreasing value 32 | /// 33 | Descending = 1, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /MoreLinq/ReverseComparer.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2016 Felipe Sateler. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System.Collections.Generic; 21 | 22 | sealed class ReverseComparer : IComparer 23 | { 24 | readonly IComparer _underlying; 25 | 26 | public ReverseComparer(IComparer underlying) 27 | { 28 | _underlying = underlying ?? Comparer.Default; 29 | } 30 | 31 | public int Compare(T x, T y) 32 | { 33 | var result = _underlying.Compare(x, y); 34 | return result < 0 ? 1 : result > 0 ? -1 : 0; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingReadOnlyCollection.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | class BreakingReadOnlyCollection : BreakingSequence, IReadOnlyCollection 24 | { 25 | readonly IReadOnlyCollection _collection; 26 | 27 | public BreakingReadOnlyCollection(params T[] values) : this ((IReadOnlyCollection) values) {} 28 | public BreakingReadOnlyCollection(IReadOnlyCollection collection) => _collection = collection; 29 | public int Count => _collection.Count; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingSequence.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Collections; 22 | using System.Collections.Generic; 23 | 24 | /// 25 | /// Enumerable sequence which throws InvalidOperationException as soon as its 26 | /// enumerator is requested. Used to check lazy evaluation. 27 | /// 28 | class BreakingSequence : IEnumerable 29 | { 30 | public IEnumerator GetEnumerator() => throw new InvalidOperationException(); 31 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /MoreLinq.Test/CurrentThreadCultureScope.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Globalization; 21 | 22 | sealed class CurrentThreadCultureScope : Scope 23 | { 24 | public CurrentThreadCultureScope(CultureInfo @new) : 25 | base(CultureInfo.CurrentCulture) 26 | { 27 | Install(@new); 28 | } 29 | 30 | protected override void Restore(CultureInfo old) 31 | { 32 | Install(old); 33 | } 34 | 35 | static void Install(CultureInfo value) 36 | { 37 | #if NET451 38 | System.Threading.Thread.CurrentThread.CurrentCulture = value; 39 | #else 40 | CultureInfo.CurrentCulture = value; 41 | #endif 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /MoreLinq/Consume.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Completely consumes the given sequence. This method uses immediate execution, 27 | /// and doesn't store any data during execution. 28 | /// 29 | /// Element type of the sequence 30 | /// Source to consume 31 | 32 | public static void Consume(this IEnumerable source) 33 | { 34 | if (source == null) throw new ArgumentNullException(nameof(source)); 35 | foreach (var element in source) 36 | { 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /MoreLinq/Experimental/ExperimentalEnumerable.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Experimental 19 | { 20 | using System.Collections.Generic; 21 | 22 | /// 23 | /// 24 | /// Provides a set of static methods for querying objects that 25 | /// implement . 26 | /// 27 | /// THE METHODS ARE EXPERIMENTAL. THEY MAY BE UNSTABLE AND 28 | /// UNTESTED. THEY MAY BE REMOVED FROM A FUTURE MAJOR OR MINOR RELEASE AND 29 | /// POSSIBLY WITHOUT NOTICE. USE THEM AT YOUR OWN RISK. THE METHODS ARE 30 | /// PUBLISHED FOR FIELD EXPERIMENTATION TO SOLICIT FEEDBACK ON THEIR 31 | /// UTILITY AND DESIGN/IMPLEMENTATION DEFECTS. 32 | /// 33 | 34 | public static partial class ExperimentalEnumerable 35 | { 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /MoreLinq/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | using System; 19 | using System.Reflection; 20 | using System.Runtime.InteropServices; 21 | 22 | [assembly: AssemblyTitle("MoreLINQ")] 23 | [assembly: AssemblyDescription("Extensions to LINQ to Objects")] 24 | [assembly: AssemblyCompany("")] 25 | [assembly: AssemblyProduct("MoreLINQ")] 26 | [assembly: AssemblyTrademark("")] 27 | [assembly: AssemblyCulture("")] 28 | 29 | // Debug or release configuration? 30 | 31 | #if DEBUG 32 | [assembly: AssemblyConfiguration("DEBUG")] 33 | #else 34 | [assembly: AssemblyConfiguration("RELEASE")] 35 | #endif 36 | 37 | // CLS compliance and COM visibility 38 | 39 | [assembly: CLSCompliant(true)] 40 | #if !NO_COM 41 | [assembly: ComVisible(false)] 42 | 43 | // ID of the typelib if this project is exposed to COM. 44 | 45 | [assembly: Guid("fc632c9d-390e-4902-8c1c-3e57b08c1d38")] 46 | #endif 47 | -------------------------------------------------------------------------------- /msbuild.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | if "%PROCESSOR_ARCHITECTURE%"=="x86" set PROGRAMS=%ProgramFiles% 4 | if defined ProgramFiles(x86) set PROGRAMS=%ProgramFiles(x86)% 5 | for %%e in (Community Professional Enterprise) do ( 6 | if exist "%PROGRAMS%\Microsoft Visual Studio\2017\%%e\MSBuild\15.0\Bin\MSBuild.exe" ( 7 | set "MSBUILD=%PROGRAMS%\Microsoft Visual Studio\2017\%%e\MSBuild\15.0\Bin\MSBuild.exe" 8 | ) 9 | ) 10 | if exist "%MSBUILD%" goto :build 11 | set MSBUILD= 12 | for %%i in (MSBuild.exe) do set MSBUILD=%%~dpnx$PATH:i 13 | if not defined MSBUILD goto :nomsbuild 14 | set MSBUILD_VERSION_MAJOR= 15 | set MSBUILD_VERSION_MINOR= 16 | for /f "delims=. tokens=1,2,3,4" %%m in ('msbuild /version /nologo') do ( 17 | set MSBUILD_VERSION_MAJOR=%%m 18 | set MSBUILD_VERSION_MINOR=%%n 19 | ) 20 | if not defined MSBUILD_VERSION_MAJOR goto :nomsbuild 21 | if not defined MSBUILD_VERSION_MINOR goto :nomsbuild 22 | if %MSBUILD_VERSION_MAJOR% lss 15 goto :nomsbuild 23 | if %MSBUILD_VERSION_MINOR% lss 1 goto :nomsbuild 24 | :build 25 | "%MSBUILD%" %* 26 | goto :EOF 27 | 28 | :nomsbuild 29 | echo>&2 Microsoft Build Engine 15.1 is required to build the solution. For 30 | echo>&2 installation instructions, see: 31 | echo>&2 https://docs.microsoft.com/en-us/visualstudio/install/use-command-line-parameters-to-install-visual-studio 32 | echo>&2 At the very least, you will want to install the MSBuilt Tool workload 33 | echo>&2 that has the identifier "Microsoft.VisualStudio.Workload.MSBuildTools": 34 | echo>&2 https://docs.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-build-tools#msbuild-tools 35 | exit /b s 36 | -------------------------------------------------------------------------------- /MoreLinq.Test/ForEachTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class ForEachTest 25 | { 26 | [Test] 27 | public void ForEachWithSequence() 28 | { 29 | var results = new List(); 30 | new[] { 1, 2, 3 }.ForEach(results.Add); 31 | results.AssertSequenceEqual(1, 2, 3); 32 | } 33 | 34 | [Test] 35 | public void ForEachIndexedWithSequence() 36 | { 37 | var valueResults = new List(); 38 | var indexResults = new List(); 39 | new[] { 9, 7, 8 }.ForEach((x, index) => { valueResults.Add(x); indexResults.Add(index); }); 40 | valueResults.AssertSequenceEqual(9, 7, 8); 41 | indexResults.AssertSequenceEqual(0, 1, 2); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingAction.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | 22 | /// 23 | /// Actions which throw NotImplementedException if they're ever called. 24 | /// 25 | static class BreakingAction 26 | { 27 | internal static Action WithoutArguments => 28 | () => throw new NotImplementedException(); 29 | 30 | internal static Action Of() => 31 | t => throw new NotImplementedException(); 32 | 33 | internal static Action Of() => 34 | (t1, t2) => throw new NotImplementedException(); 35 | 36 | internal static Action Of() => 37 | (t1, t2, t3) => throw new NotImplementedException(); 38 | 39 | internal static Action Of() => 40 | (t1, t2, t3, t4) => throw new NotImplementedException(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /MoreLinq.Test/PairwiseTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class PairwiseTest 24 | { 25 | [Test] 26 | public void PairwiseIsLazy() 27 | { 28 | new BreakingSequence().Pairwise(BreakingFunc.Of()); 29 | } 30 | 31 | [TestCase(0)] 32 | [TestCase(1)] 33 | public void PairwiseWithSequenceShorterThanTwo(int count) 34 | { 35 | var source = Enumerable.Range(0, count); 36 | var result = source.Pairwise(BreakingFunc.Of()); 37 | 38 | Assert.That(result, Is.Empty); 39 | } 40 | 41 | [Test] 42 | public void PairwiseWideSourceSequence() 43 | { 44 | var result = new[] { "a", "b", "c", "d" }.Pairwise((x, y) => x + y); 45 | result.AssertSequenceEqual("ab", "bc", "cd"); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingFunc.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | 22 | /// 23 | /// Functions which throw NotImplementedException if they're ever called. 24 | /// 25 | static class BreakingFunc 26 | { 27 | internal static Func Of() => 28 | () => throw new NotImplementedException(); 29 | 30 | internal static Func Of() => 31 | t => throw new NotImplementedException(); 32 | 33 | internal static Func Of() => 34 | (t1, t2) => throw new NotImplementedException(); 35 | 36 | internal static Func Of() => 37 | (t1, t2, t3) => throw new NotImplementedException(); 38 | 39 | internal static Func Of() => 40 | (t1, t2, t3, t4) => throw new NotImplementedException(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /MoreLinq.Test/BreakingCollection.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | class BreakingCollection : BreakingSequence, ICollection 24 | { 25 | protected readonly IList List; 26 | 27 | public BreakingCollection(params T[] values) : this ((IList) values) {} 28 | public BreakingCollection(IList list) => List = list; 29 | public BreakingCollection(int count) : 30 | this(Enumerable.Repeat(default(T), count).ToList()) {} 31 | 32 | public int Count => List.Count; 33 | 34 | public void Add(T item) => throw new NotImplementedException(); 35 | public void Clear() => throw new NotImplementedException(); 36 | public bool Contains(T item) => List.Contains(item); 37 | public void CopyTo(T[] array, int arrayIndex) => List.CopyTo(array, arrayIndex); 38 | public bool Remove(T item) => throw new NotImplementedException(); 39 | public bool IsReadOnly => true; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /MoreLinq.Test/ToDelimitedStringTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class ToDelimitedStringTest 24 | { 25 | [Test] 26 | public void ToDelimitedStringWithNonEmptySequenceAndDelimiter() 27 | { 28 | var result = new[] { 1, 2, 3 }.ToDelimitedString("-"); 29 | Assert.That(result, Is.EqualTo("1-2-3")); 30 | } 31 | 32 | [Test] 33 | public void ToDelimitedStringWithNonEmptySequenceContainingNulls() 34 | { 35 | var result = new object[] { 1, null, "foo", true }.ToDelimitedString(","); 36 | Assert.That(result, Is.EqualTo("1,,foo,True")); 37 | } 38 | 39 | [Test] 40 | public void ToDelimitedStringWithNonEmptySequenceContainingNullsAtStart() 41 | { 42 | // See: https://github.com/morelinq/MoreLINQ/issues/43 43 | var result = new object[] { null, null, "foo" }.ToDelimitedString(","); 44 | Assert.That(result, Is.EqualTo(",,foo")); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /MoreLinq.Test/SampleData.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Collections.ObjectModel; 23 | 24 | /// 25 | /// Data and functions to use throughout tests. 26 | /// 27 | static class SampleData 28 | { 29 | internal static readonly ReadOnlyCollection Strings = new ReadOnlyCollection( 30 | new[] { "ax", "hello", "world", "aa", "ab", "ay", "az" }); 31 | 32 | internal static readonly ReadOnlyCollection Values = 33 | new ReadOnlyCollection(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); 34 | 35 | internal static readonly Func Plus = (a, b) => a + b; 36 | internal static readonly Func Mul = (a, b) => a * b; 37 | 38 | internal static readonly IComparer ReverseCharComparer = new ReverseCharComparerImpl(); 39 | 40 | class ReverseCharComparerImpl : IComparer 41 | { 42 | public int Compare(char x, char y) => y.CompareTo(x); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: csharp 2 | os: 3 | - linux 4 | - osx 5 | osx_image: xcode8.3 6 | solution: MoreLinq.sln 7 | mono: 5.0.1 8 | dist: trusty 9 | sudo: required 10 | dotnet: 2.1.500 11 | env: 12 | - CONFIGURATION=Debug 13 | - CONFIGURATION=Release 14 | addons: 15 | apt: 16 | sources: 17 | - sourceline: 'deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-trusty-prod trusty main' 18 | key_url: 'https://packages.microsoft.com/keys/microsoft.asc' 19 | packages: 20 | - dotnet-hostfxr-1.0.1 21 | - dotnet-sharedframework-microsoft.netcore.app-1.0.5 22 | 23 | before_install: 24 | - dotnet --info 25 | - msbuild /version 26 | - | 27 | if [ "$TRAVIS_OS_NAME" == "osx" ] || [ `uname` == "Darwin" ]; then 28 | # Handle too many files on OS X 29 | ulimit -n 4096 30 | # Install dotnet core 1 sdk 31 | wget --retry-connrefused --waitretry=1 -O /tmp/dn1.pkg 'https://download.microsoft.com/download/B/9/F/B9F1AF57-C14A-4670-9973-CDF47209B5BF/dotnet-dev-osx-x64.1.0.4.pkg' 32 | sudo installer -pkg /tmp/dn1.pkg -target / 33 | fi 34 | 35 | install: 36 | - dotnet restore 37 | - npm install -g eclint 38 | 39 | before_script: 40 | - git rm .editorconfig 41 | - eclint check -n "**/*.{cs,tt,cmd,sh,md,txt,yml}" 42 | - eclint check -w "**/*.{cs,tt,cmd,sh,md,txt,yml,json,sln,csproj,shfbproj}" 43 | - git reset --hard 44 | 45 | script: 46 | - | 47 | if grep --extended-regexp '^[[:space:]]*using[[:space:]]+System\.Linq;' $(ls MoreLinq.Test/*Test.cs); then 48 | echo "System.Linq import found, failing the build!" >&2 49 | exit 1 50 | fi 51 | - ./build.sh /v:m /p:Configuration=$CONFIGURATION 52 | - dotnet exec MoreLinq.Test/bin/$CONFIGURATION/netcoreapp1.0/MoreLinq.Test.dll 53 | - dotnet exec MoreLinq.Test/bin/$CONFIGURATION/netcoreapp2.0/MoreLinq.Test.dll 54 | - dotnet exec MoreLinq.Test/bin/$CONFIGURATION/netcoreapp2.1/MoreLinq.Test.dll 55 | - mono MoreLinq.Test/bin/$CONFIGURATION/net451/MoreLinq.Test.exe 56 | -------------------------------------------------------------------------------- /MoreLinq.Test/SkipLastTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class SkipLastTest 24 | { 25 | [TestCase( 0)] 26 | [TestCase(-1)] 27 | public void SkipLastWithCountLesserThanOne(int skip) 28 | { 29 | var numbers = Enumerable.Range(1, 5); 30 | 31 | Assert.That(numbers.SkipLast(skip), Is.EqualTo(numbers)); 32 | } 33 | 34 | [Test] 35 | public void SkipLast() 36 | { 37 | const int take = 100; 38 | const int skip = 20; 39 | 40 | var sequence = Enumerable.Range(1, take); 41 | 42 | var expectations = sequence.Take(take - skip); 43 | 44 | Assert.That(expectations, Is.EqualTo(sequence.SkipLast(skip))); 45 | } 46 | 47 | [TestCase(5)] 48 | [TestCase(6)] 49 | public void SkipLastWithSequenceShorterThanCount(int skip) 50 | { 51 | Assert.That(Enumerable.Range(1, 5).SkipLast(skip), Is.Empty); 52 | } 53 | 54 | [Test] 55 | public void SkipLastIsLazy() 56 | { 57 | new BreakingSequence().SkipLast(1); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /MoreLinq.Test/WatchableEnumerator.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Collections; 22 | using System.Collections.Generic; 23 | 24 | partial class TestExtensions 25 | { 26 | public static WatchableEnumerator AsWatchtable(this IEnumerator source) => 27 | new WatchableEnumerator(source); 28 | } 29 | 30 | sealed class WatchableEnumerator : IEnumerator 31 | { 32 | readonly IEnumerator _source; 33 | 34 | public event EventHandler Disposed; 35 | public event EventHandler MoveNextCalled; 36 | 37 | public WatchableEnumerator(IEnumerator source) => 38 | _source = source ?? throw new ArgumentNullException(nameof(source)); 39 | 40 | public T Current => _source.Current; 41 | object IEnumerator.Current => Current; 42 | public void Reset() => _source.Reset(); 43 | 44 | public bool MoveNext() 45 | { 46 | MoveNextCalled?.Invoke(this, EventArgs.Empty); 47 | return _source.MoveNext(); 48 | } 49 | 50 | public void Dispose() 51 | { 52 | _source.Dispose(); 53 | Disposed?.Invoke(this, EventArgs.Empty); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /MoreLinq/Evaluate.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Felipe Sateler. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns a sequence containing the values resulting from invoking (in order) each function in the source sequence of functions. 28 | /// 29 | /// 30 | /// This operator uses deferred execution and streams the results. 31 | /// If the resulting sequence is enumerated multiple times, the functions will be 32 | /// evaluated multiple times too. 33 | /// 34 | /// The type of the object returned by the functions. 35 | /// The functions to evaluate. 36 | /// A sequence with results from invoking . 37 | /// When is null. 38 | 39 | public static IEnumerable Evaluate(this IEnumerable> functions) => 40 | from f in functions ?? throw new ArgumentNullException(nameof(functions)) 41 | select f(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /MoreLinq.Test/EvaluateTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Felipe Sateler. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using NUnit.Framework; 22 | 23 | class EvaluateTest 24 | { 25 | [Test] 26 | public void TestEvaluateIsLazy() 27 | { 28 | new BreakingSequence>().Evaluate(); 29 | } 30 | 31 | [Test] 32 | public void TestEvaluateInvokesMethods() 33 | { 34 | var factories = new Func[] 35 | { 36 | () => -2, 37 | () => 4, 38 | () => int.MaxValue, 39 | () => int.MinValue, 40 | }; 41 | var results = factories.Evaluate(); 42 | 43 | results.AssertSequenceEqual(-2, 4, int.MaxValue, int.MinValue); 44 | } 45 | 46 | [Test] 47 | public void TestEvaluateInvokesMethodsMultipleTimes() 48 | { 49 | var evals = 0; 50 | var factories = new Func[] 51 | { 52 | () => { evals++; return -2; }, 53 | }; 54 | var results = factories.Evaluate(); 55 | 56 | results.Consume(); 57 | results.Consume(); 58 | results.Consume(); 59 | 60 | Assert.That(evals, Is.EqualTo(3)); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{build}' 2 | image: Visual Studio 2017 3 | skip_commits: 4 | files: 5 | - '*.md' 6 | - '*.txt' 7 | - '.editorconfig' 8 | - lic/* 9 | environment: 10 | DOTNET_CLI_TELEMETRY_OPTOUT: true 11 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true 12 | install: 13 | - ps: Install-Product node 6 14 | - npm install -g eclint 15 | - git rm .editorconfig 16 | - eclint check -n "**/*.{cs,tt,cmd,sh,md,txt,yml}" 17 | - eclint check -w "**/*.{cs,tt,cmd,sh,md,txt,yml,json,sln,csproj,shfbproj}" 18 | - git reset --hard 19 | - ps: tools\dotnet-install.ps1 -Version ((type .\global.json | ConvertFrom-Json).sdk.version) 20 | before_build: 21 | - dotnet --info 22 | build_script: 23 | - ps: >- 24 | grep --extended-regexp '^[[:space:]]*using[[:space:]]+System\.Linq;' (dir MoreLinq.Test\*Test.cs) 25 | 26 | if ($LASTEXITCODE -eq 0) { 27 | throw 'Unit tests should not import System.Linq' 28 | } 29 | 30 | $id = $env:APPVEYOR_REPO_COMMIT_TIMESTAMP -replace '([-:]|\.0+Z)', '' 31 | 32 | $id = $id.Substring(0, 13) 33 | 34 | cmd /c call pack.cmd ci-$id 35 | 36 | if ($LASTEXITCODE -ne 0) { 37 | throw "Building/Packing failed with an exit code of $LASTEXITCODE." 38 | } 39 | 40 | $diff = git diff --ignore-all-space --exit-code 2>&1 41 | 42 | $diff | % { if ($_ -is [string]) { $_ } else { [string]$_ } } | echo 43 | 44 | if ($LASTEXITCODE -ne 0) { 45 | throw "New code was generated during build that's not been committed." 46 | } 47 | test_script: 48 | - cmd: test.cmd 49 | artifacts: 50 | - path: dist\*.nupkg 51 | deploy: 52 | - provider: NuGet 53 | server: https://www.myget.org/F/morelinq/api/v2/package 54 | api_key: 55 | secure: fhGwXyO35FSshRzs5GWmF1LJTrd1sIqmS/jNCSfO2LfOciuYAKiXuFMYZFGiTAl+ 56 | symbol_server: https://www.myget.org/F/morelinq/symbols/api/v2/package 57 | on: 58 | branch: master 59 | notifications: 60 | - provider: Email 61 | to: 62 | - morelinq-roll@googlegroups.com 63 | on_build_success: true 64 | on_build_failure: true 65 | on_build_status_changed: false 66 | -------------------------------------------------------------------------------- /MoreLinq.Test/PipeTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | using System.Text; 22 | using NUnit.Framework; 23 | 24 | [TestFixture] 25 | public class PipeTest 26 | { 27 | [Test] 28 | public void PipeWithSequence() 29 | { 30 | var results = new List(); 31 | var returned = new[] { 1, 2, 3 }.Pipe(results.Add); 32 | // Lazy - nothing has executed yet 33 | Assert.That(results, Is.Empty); 34 | returned.AssertSequenceEqual(1, 2, 3); 35 | // Now it has... 36 | results.AssertSequenceEqual(1, 2, 3); 37 | } 38 | 39 | [Test] 40 | public void PipeIsLazy() 41 | { 42 | new BreakingSequence().Pipe(BreakingAction.Of()); 43 | } 44 | 45 | [Test] 46 | public void PipeActionOccursBeforeYield() 47 | { 48 | var source = new[] { new StringBuilder(), new StringBuilder() }; 49 | // The action will occur "in" the pipe, so by the time Where gets it, the 50 | // sequence will be empty. 51 | Assert.That(source.Pipe(sb => sb.Append("x")) 52 | .Where(x => x.Length == 0), 53 | Is.Empty); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /MoreLinq.Test/IndexTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class IndexTest 24 | { 25 | [Test] 26 | public void IndexIsLazy() 27 | { 28 | var bs = new BreakingSequence(); 29 | bs.Index(); 30 | bs.Index(0); 31 | } 32 | 33 | [Test] 34 | public void IndexSequence() 35 | { 36 | const string one = "one"; 37 | const string two = "two"; 38 | const string three = "three"; 39 | var result = new[] { one, two, three }.Index(); 40 | result.AssertSequenceEqual( 41 | KeyValuePair.Create(0, one), 42 | KeyValuePair.Create(1, two), 43 | KeyValuePair.Create(2, three)); 44 | } 45 | 46 | [Test] 47 | public void IndexSequenceStartIndex() 48 | { 49 | const string one = "one"; 50 | const string two = "two"; 51 | const string three = "three"; 52 | var result = new[] { one, two, three }.Index(10); 53 | result.AssertSequenceEqual( 54 | KeyValuePair.Create(10, one), 55 | KeyValuePair.Create(11, two), 56 | KeyValuePair.Create(12, three)); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /MoreLinq/GenerateByIndex.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns a sequence of values based on indexes. 28 | /// 29 | /// 30 | /// The type of the value returned by 31 | /// and therefore the elements of the generated sequence. 32 | /// 33 | /// Generation function to apply to each index. 34 | /// A sequence of generated results. 35 | /// 36 | /// 37 | /// The sequence is (practically) infinite where the index ranges from 38 | /// zero to inclusive. 39 | /// 40 | /// This function defers execution and streams the results. 41 | /// 42 | 43 | public static IEnumerable GenerateByIndex(Func generator) 44 | { 45 | if (generator == null) throw new ArgumentNullException(nameof(generator)); 46 | 47 | return MoreEnumerable.Sequence(0, int.MaxValue) 48 | .Select(generator); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /MoreLinq/MoreEnumerable.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | /// 24 | /// Provides a set of static methods for querying objects that 25 | /// implement . 26 | /// 27 | 28 | public static partial class MoreEnumerable 29 | { 30 | static int? TryGetCollectionCount(this IEnumerable source) 31 | { 32 | if (source == null) throw new ArgumentNullException(nameof(source)); 33 | 34 | return source is ICollection collection ? collection.Count 35 | : source is IReadOnlyCollection readOnlyCollection ? readOnlyCollection.Count 36 | : (int?)null; 37 | } 38 | 39 | static int CountUpTo(this IEnumerable source, int max) 40 | { 41 | if (source == null) throw new ArgumentNullException(nameof(source)); 42 | if (max < 0) throw new ArgumentOutOfRangeException(nameof(max), "The maximum count argument cannot be negative."); 43 | 44 | var count = 0; 45 | 46 | using (var e = source.GetEnumerator()) 47 | { 48 | while (count < max && e.MoveNext()) 49 | { 50 | count++; 51 | } 52 | } 53 | 54 | return count; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /MoreLinq/SkipLast.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Bypasses a specified number of elements at the end of the sequence. 28 | /// 29 | /// Type of the source sequence 30 | /// The source sequence. 31 | /// The number of elements to bypass at the end of the source sequence. 32 | /// 33 | /// An containing the source sequence elements except for the bypassed ones at the end. 34 | /// 35 | 36 | public static IEnumerable SkipLast(this IEnumerable source, int count) 37 | { 38 | if (source == null) throw new ArgumentNullException(nameof(source)); 39 | 40 | if (count < 1) 41 | return source; 42 | 43 | return 44 | source.TryGetCollectionCount() is int collectionCount 45 | ? source.Take(collectionCount - count) 46 | : source.CountDown(count, (e, cd) => (Element: e, Countdown: cd )) 47 | .TakeWhile(e => e.Countdown == null) 48 | .Select(e => e.Element); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /MoreLinq/Prepend.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Prepends a single value to a sequence. 27 | /// 28 | /// The type of the elements of . 29 | /// The sequence to prepend to. 30 | /// The value to prepend. 31 | /// 32 | /// Returns a sequence where a value is prepended to it. 33 | /// 34 | /// 35 | /// This operator uses deferred execution and streams its results. 36 | /// 37 | /// 41 | /// The result variable, when iterated over, will yield 42 | /// 0, 1, 2 and 3, in turn. 43 | 44 | public static IEnumerable Prepend(this IEnumerable source, TSource value) 45 | { 46 | if (source == null) throw new ArgumentNullException(nameof(source)); 47 | return source is PendNode node 48 | ? node.Prepend(value) 49 | : PendNode.WithSource(source).Prepend(value); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /MoreLinq.Test/TakeUntilTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class TakeUntilTest 24 | { 25 | [Test] 26 | public void TakeUntilPredicateNeverFalse() 27 | { 28 | var sequence = Enumerable.Range(0, 5).TakeUntil(x => x != 100); 29 | sequence.AssertSequenceEqual(0); 30 | } 31 | 32 | [Test] 33 | public void TakeUntilPredicateNeverTrue() 34 | { 35 | var sequence = Enumerable.Range(0, 5).TakeUntil(x => x == 100); 36 | sequence.AssertSequenceEqual(0, 1, 2, 3, 4); 37 | } 38 | 39 | [Test] 40 | public void TakeUntilPredicateBecomesTrueHalfWay() 41 | { 42 | var sequence = Enumerable.Range(0, 5).TakeUntil(x => x == 2); 43 | sequence.AssertSequenceEqual(0, 1, 2); 44 | } 45 | 46 | [Test] 47 | public void TakeUntilEvaluatesSourceLazily() 48 | { 49 | new BreakingSequence().TakeUntil(x => x.Length == 0); 50 | } 51 | 52 | [Test] 53 | public void TakeUntilEvaluatesPredicateLazily() 54 | { 55 | // Predicate would explode at x == 0, but we never need to evaluate it due to the Take call. 56 | var sequence = Enumerable.Range(-2, 5).TakeUntil(x => 1 / x == 1).Take(3); 57 | sequence.AssertSequenceEqual(-2, -1, 0); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /MoreLinq.Test/SkipUntilTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class SkipUntilTest 24 | { 25 | [Test] 26 | public void SkipUntilPredicateNeverFalse() 27 | { 28 | var sequence = Enumerable.Range(0, 5).SkipUntil(x => x != 100); 29 | sequence.AssertSequenceEqual(1, 2, 3, 4); 30 | } 31 | 32 | [Test] 33 | public void SkipUntilPredicateNeverTrue() 34 | { 35 | var sequence = Enumerable.Range(0, 5).SkipUntil(x => x == 100); 36 | Assert.That(sequence, Is.Empty); 37 | } 38 | 39 | [Test] 40 | public void SkipUntilPredicateBecomesTrueHalfWay() 41 | { 42 | var sequence = Enumerable.Range(0, 5).SkipUntil(x => x == 2); 43 | sequence.AssertSequenceEqual(3, 4); 44 | } 45 | 46 | [Test] 47 | public void SkipUntilEvaluatesSourceLazily() 48 | { 49 | new BreakingSequence().SkipUntil(x => x.Length == 0); 50 | } 51 | 52 | [Test] 53 | public void SkipUntilEvaluatesPredicateLazily() 54 | { 55 | // Predicate would explode at x == 0, but we never need to evaluate it as we've 56 | // started returning items after -1. 57 | var sequence = Enumerable.Range(-2, 5).SkipUntil(x => 1 / x == -1); 58 | sequence.AssertSequenceEqual(0, 1, 2); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /MoreLinq/TakeEvery.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns every N-th element of a sequence. 28 | /// 29 | /// Type of the source sequence 30 | /// Source sequence 31 | /// Number of elements to bypass before returning the next element. 32 | /// 33 | /// A sequence with every N-th element of the input sequence. 34 | /// 35 | /// 36 | /// This operator uses deferred execution and streams its results. 37 | /// 38 | /// 39 | /// 43 | /// The result variable, when iterated over, will yield 1, 3 and 5, in turn. 44 | /// 45 | 46 | public static IEnumerable TakeEvery(this IEnumerable source, int step) 47 | { 48 | if (source == null) throw new ArgumentNullException(nameof(source)); 49 | if (step <= 0) throw new ArgumentOutOfRangeException(nameof(step)); 50 | return source.Where((e, i) => i % step == 0); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /MoreLinq.Test/FillBackwardTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class FillBackwardTest 24 | { 25 | [Test] 26 | public void FillBackwardIsLazy() 27 | { 28 | new BreakingSequence().FillBackward(); 29 | } 30 | 31 | [Test] 32 | public void FillBackward() 33 | { 34 | int? na = null; 35 | var input = new[] { na, na, 1, 2, na, na, na, 3, 4, na, na }; 36 | var result = input.FillBackward(); 37 | Assert.That(result, Is.EqualTo(new[] { 1, 1, 1, 2, 3, 3, 3, 3, 4, na, na })); 38 | } 39 | 40 | [Test] 41 | public void FillBackwardWithFillSelector() 42 | { 43 | var xs = new[] { 0, 0, 1, 2, 0, 0, 0, 3, 4, 0, 0 }; 44 | 45 | var result = 46 | xs.Select(x => new { X = x, Y = x }) 47 | .FillBackward(e => e.X == 0, (m, nm) => new { m.X, nm.Y }); 48 | 49 | Assert.That(result, Is.EqualTo(new[] 50 | { 51 | new { X = 0, Y = 1 }, 52 | new { X = 0, Y = 1 }, 53 | new { X = 1, Y = 1 }, 54 | new { X = 2, Y = 2 }, 55 | new { X = 0, Y = 3 }, 56 | new { X = 0, Y = 3 }, 57 | new { X = 0, Y = 3 }, 58 | new { X = 3, Y = 3 }, 59 | new { X = 4, Y = 4 }, 60 | new { X = 0, Y = 0 }, 61 | new { X = 0, Y = 0 }, 62 | })); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /MoreLinq.Test/GenerateTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class GenerateTest 24 | { 25 | [Test] 26 | public void GenerateTerminatesWhenCheckReturnsFalse() 27 | { 28 | var result = MoreEnumerable.Generate(1, n => n + 2).TakeWhile(n => n < 10); 29 | 30 | result.AssertSequenceEqual(1, 3, 5, 7, 9); 31 | } 32 | 33 | [Test] 34 | public void GenerateProcessesNonNumerics() 35 | { 36 | var result = MoreEnumerable.Generate("", s => s + 'a').TakeWhile(s => s.Length < 5); 37 | 38 | result.AssertSequenceEqual("", "a", "aa", "aaa", "aaaa"); 39 | } 40 | 41 | [Test] 42 | public void GenerateIsLazy() 43 | { 44 | MoreEnumerable.Generate(0, BreakingFunc.Of()); 45 | } 46 | 47 | [Test] 48 | public void GenerateFuncIsNotInvokedUnnecessarily() 49 | { 50 | MoreEnumerable.Generate(0, BreakingFunc.Of()) 51 | .Take(1) 52 | .Consume(); 53 | } 54 | 55 | [Test] 56 | public void GenerateByIndexIsLazy() 57 | { 58 | MoreEnumerable.GenerateByIndex(BreakingFunc.Of()); 59 | } 60 | 61 | [Test] 62 | public void GenerateByIndex() 63 | { 64 | var sequence = MoreEnumerable.GenerateByIndex(x => x.ToString()).Take(3); 65 | sequence.AssertSequenceEqual("0", "1", "2"); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /MoreLinq.Test/DistinctByTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class DistinctByTest 25 | { 26 | [Test] 27 | public void DistinctBy() 28 | { 29 | string[] source = { "first", "second", "third", "fourth", "fifth" }; 30 | var distinct = source.DistinctBy(word => word.Length); 31 | distinct.AssertSequenceEqual("first", "second"); 32 | } 33 | 34 | [Test] 35 | public void DistinctByIsLazy() 36 | { 37 | new BreakingSequence().DistinctBy(BreakingFunc.Of()); 38 | } 39 | 40 | [Test] 41 | public void DistinctByWithComparer() 42 | { 43 | string[] source = { "first", "FIRST", "second", "second", "third" }; 44 | var distinct = source.DistinctBy(word => word, StringComparer.OrdinalIgnoreCase); 45 | distinct.AssertSequenceEqual("first", "second", "third"); 46 | } 47 | 48 | [Test] 49 | public void DistinctByNullComparer() 50 | { 51 | string[] source = { "first", "second", "third", "fourth", "fifth" }; 52 | var distinct = source.DistinctBy(word => word.Length, null); 53 | distinct.AssertSequenceEqual("first", "second"); 54 | } 55 | 56 | [Test] 57 | public void DistinctByIsLazyWithComparer() 58 | { 59 | new BreakingSequence() 60 | .DistinctBy(BreakingFunc.Of(), StringComparer.Ordinal); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /MoreLinq.Test/TakeEveryTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class TakeEveryTest 24 | { 25 | [Test] 26 | public void TakeEveryNegativeSkip() 27 | { 28 | AssertThrowsArgument.OutOfRangeException("step",() => 29 | new object[0].TakeEvery(-1)); 30 | } 31 | 32 | [Test] 33 | public void TakeEveryOutOfRangeZeroStep() 34 | { 35 | AssertThrowsArgument.OutOfRangeException("step", () => 36 | new object[0].TakeEvery(0)); 37 | } 38 | 39 | [Test] 40 | public void TakeEveryEmptySequence() 41 | { 42 | Assert.That(new object[0].TakeEvery(1), Is.Empty); 43 | } 44 | 45 | [Test] 46 | public void TakeEveryNonEmptySequence() 47 | { 48 | var result = new[] { 1, 2, 3, 4, 5 }.TakeEvery(1); 49 | result.AssertSequenceEqual(1, 2, 3, 4, 5); 50 | } 51 | 52 | [Test] 53 | public void TakeEveryOtherOnNonEmptySequence() 54 | { 55 | var result = new[] { 1, 2, 3, 4, 5 }.TakeEvery(2); 56 | result.AssertSequenceEqual(1, 3, 5); 57 | } 58 | 59 | [Test] 60 | public void TakeEveryThirdOnNonEmptySequence() 61 | { 62 | var result = new[] { 1, 2, 3, 4, 5 }.TakeEvery(3); 63 | result.AssertSequenceEqual(1, 4); 64 | } 65 | 66 | [Test] 67 | public void TakeEveryIsLazy() 68 | { 69 | new BreakingSequence().TakeEvery(1); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /MoreLinq/Acquire.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2012 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Ensures that a source sequence of 27 | /// objects are all acquired successfully. If the acquisition of any 28 | /// one fails then those successfully 29 | /// acquired till that point are disposed. 30 | /// 31 | /// Type of elements in sequence. 32 | /// Source sequence of objects. 33 | /// 34 | /// Returns an array of all the acquired 35 | /// objects in source order. 36 | /// 37 | /// 38 | /// This operator executes immediately. 39 | /// 40 | 41 | public static TSource[] Acquire(this IEnumerable source) 42 | where TSource : IDisposable 43 | { 44 | if (source == null) throw new ArgumentNullException(nameof(source)); 45 | 46 | var disposables = new List(); 47 | try 48 | { 49 | disposables.AddRange(source); 50 | return disposables.ToArray(); 51 | } 52 | catch 53 | { 54 | foreach (var disposable in disposables) 55 | disposable.Dispose(); 56 | throw; 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /MoreLinq/ListLike.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | /// 25 | /// Represents an list-like (indexable) data structure. 26 | /// 27 | 28 | interface IListLike 29 | { 30 | int Count { get; } 31 | T this[int index] { get; } 32 | } 33 | 34 | static class ListLike 35 | { 36 | public static IListLike ToListLike(this IEnumerable source) 37 | => source.TryAsListLike() ?? new List(source.ToList()); 38 | 39 | public static IListLike TryAsListLike(this IEnumerable source) 40 | => source is null ? throw new ArgumentNullException(nameof(source)) 41 | : source is IList list ? new List(list) 42 | : source is IReadOnlyList readOnlyList ? new ReadOnlyList(readOnlyList) 43 | : (IListLike) null; 44 | 45 | sealed class List : IListLike 46 | { 47 | readonly IList _list; 48 | public List(IList list) => _list = list ?? throw new ArgumentNullException(nameof(list)); 49 | public int Count => _list.Count; 50 | public T this[int index] => _list[index]; 51 | } 52 | 53 | sealed class ReadOnlyList : IListLike 54 | { 55 | readonly IReadOnlyList _list; 56 | public ReadOnlyList(IReadOnlyList list) => _list = list ?? throw new ArgumentNullException(nameof(list)); 57 | public int Count => _list.Count; 58 | public T this[int index] => _list[index]; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /MoreLinq/Pipe.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Executes the given action on each element in the source sequence 27 | /// and yields it. 28 | /// 29 | /// The type of the elements in the sequence 30 | /// The sequence of elements 31 | /// The action to execute on each element 32 | /// A sequence with source elements in their original order. 33 | /// 34 | /// The returned sequence is essentially a duplicate of 35 | /// the original, but with the extra action being executed while the 36 | /// sequence is evaluated. The action is always taken before the element 37 | /// is yielded, so any changes made by the action will be visible in the 38 | /// returned sequence. This operator uses deferred execution and streams it results. 39 | /// 40 | 41 | public static IEnumerable Pipe(this IEnumerable source, Action action) 42 | { 43 | if (source == null) throw new ArgumentNullException(nameof(source)); 44 | if (action == null) throw new ArgumentNullException(nameof(action)); 45 | 46 | return _(); IEnumerable _() 47 | { 48 | foreach (var element in source) 49 | { 50 | action(element); 51 | yield return element; 52 | } 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /MoreLinq.Test/SplitTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class SplitTest 24 | { 25 | [Test] 26 | public void SplitWithSeparatorAndResultTransformation() 27 | { 28 | var result = "the quick brown fox".ToCharArray().Split(' ', chars => new string(chars.ToArray())); 29 | result.AssertSequenceEqual("the", "quick", "brown", "fox"); 30 | } 31 | 32 | [Test] 33 | public void SplitUptoMaxCount() 34 | { 35 | var result = "the quick brown fox".ToCharArray().Split(' ', 2, chars => new string(chars.ToArray())); 36 | result.AssertSequenceEqual("the", "quick", "brown fox"); 37 | } 38 | 39 | [Test] 40 | public void SplitWithSeparatorSelector() 41 | { 42 | var result = new int?[] { 1, 2, null, 3, null, 4, 5, 6 }.Split(n => n == null); 43 | using (var reader = result.Read()) 44 | { 45 | reader.Read().AssertSequenceEqual(1, 2); 46 | reader.Read().AssertSequenceEqual(3); 47 | reader.Read().AssertSequenceEqual(4, 5, 6); 48 | reader.ReadEnd(); 49 | } 50 | } 51 | 52 | [Test] 53 | public void SplitWithSeparatorSelectorUptoMaxCount() 54 | { 55 | var result = new int?[] { 1, 2, null, 3, null, 4, 5, 6 }.Split(n => n == null, 1); 56 | using (var reader = result.Read()) 57 | { 58 | reader.Read().AssertSequenceEqual(1, 2); 59 | reader.Read().AssertSequenceEqual(3, null, 4, 5, 6); 60 | reader.ReadEnd(); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /MoreLinq/Generate.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Chris Ammerman. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Returns a sequence of values consecutively generated by a generator function. 27 | /// 28 | /// Type of elements to generate. 29 | /// Value of first element in sequence 30 | /// 31 | /// Generator function which takes the previous series element and uses it to generate the next element. 32 | /// 33 | /// A sequence containing the generated values. 34 | /// 35 | /// This function defers element generation until needed and streams the results. 36 | /// 37 | /// 38 | /// n * n).Take(5); 40 | /// ]]> 41 | /// The result variable, when iterated over, will yield 2, 4, 16, 256, and 65536, in turn. 42 | /// 43 | 44 | public static IEnumerable Generate(TResult initial, Func generator) 45 | { 46 | if (generator == null) throw new ArgumentNullException(nameof(generator)); 47 | 48 | return _(); IEnumerable _() 49 | { 50 | var current = initial; 51 | while (true) 52 | { 53 | yield return current; 54 | current = generator(current); 55 | } 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /MoreLinq/NestedLoops.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2010 Leopold Bushkin. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | public static partial class MoreEnumerable 25 | { 26 | // This extension method was developed (primarily) to support the 27 | // implementation of the Permutations() extension methods. 28 | 29 | /// 30 | /// Produces a sequence from an action based on the dynamic generation of N nested loops 31 | /// whose iteration counts are defined by a sequence of loop counts. 32 | /// 33 | /// Action delegate for which to produce a nested loop sequence 34 | /// A sequence of loop repetition counts 35 | /// A sequence of Action representing the expansion of a set of nested loops 36 | 37 | static IEnumerable NestedLoops(this Action action, IEnumerable loopCounts) 38 | { 39 | if (action == null) throw new ArgumentNullException(nameof(action)); 40 | if (loopCounts == null) throw new ArgumentNullException(nameof(loopCounts)); 41 | 42 | return _(); IEnumerable _() 43 | { 44 | var count = loopCounts.Assert(n => n >= 0, 45 | n => new InvalidOperationException("Invalid loop count (must be greater than or equal to zero).")) 46 | .DefaultIfEmpty() 47 | .Aggregate((acc, x) => acc * x); 48 | 49 | for (var i = 0; i < count; i++) 50 | yield return action; 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /MoreLinq.Test/TagFirstLastTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class TagFirstLastTest 24 | { 25 | [Test] 26 | public void TagFirstLastIsLazy() 27 | { 28 | new BreakingSequence().TagFirstLast(BreakingFunc.Of()); 29 | } 30 | 31 | [Test] 32 | public void TagFirstLastWithSourceSequenceOfOne() 33 | { 34 | var source = new[] { 123 }; 35 | source.TagFirstLast((item, isFirst, isLast) => new { Item = item, IsFirst = isFirst, IsLast = isLast }) 36 | .AssertSequenceEqual(new { Item = 123, IsFirst = true, IsLast = true }); 37 | } 38 | 39 | [Test] 40 | public void TagFirstLastWithSourceSequenceOfTwo() 41 | { 42 | var source = new[] { 123, 456 }; 43 | source.TagFirstLast((item, isFirst, isLast) => new { Item = item, IsFirst = isFirst, IsLast = isLast }) 44 | .AssertSequenceEqual(new { Item = 123, IsFirst = true, IsLast = false }, 45 | new { Item = 456, IsFirst = false, IsLast = true }); 46 | } 47 | 48 | [Test] 49 | public void TagFirstLastWithSourceSequenceOfThree() 50 | { 51 | var source = new[] { 123, 456, 789 }; 52 | source.TagFirstLast((item, isFirst, isLast) => new { Item = item, IsFirst = isFirst, IsLast = isLast }) 53 | .AssertSequenceEqual(new { Item = 123, IsFirst = true, IsLast = false }, 54 | new { Item = 456, IsFirst = false, IsLast = false }, 55 | new { Item = 789, IsFirst = false, IsLast = true }); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /MoreLinq.Test/PreScanTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class PreScanTest 24 | { 25 | [Test] 26 | public void PreScanIsLazy() 27 | { 28 | new BreakingSequence().PreScan(BreakingFunc.Of(), 0); 29 | } 30 | 31 | [Test] 32 | public void PreScanWithEmptySequence() 33 | { 34 | var source = Enumerable.Empty(); 35 | var result = source.PreScan(BreakingFunc.Of(), 0); 36 | 37 | Assert.That(result, Is.Empty); 38 | } 39 | 40 | [Test] 41 | public void PreScanWithSingleElement() 42 | { 43 | var source = new[] { 111 }; 44 | var result = source.PreScan(BreakingFunc.Of(), 999); 45 | result.AssertSequenceEqual(999); 46 | } 47 | 48 | [Test] 49 | public void PreScanSum() 50 | { 51 | var result = SampleData.Values.PreScan(SampleData.Plus, 0); 52 | result.AssertSequenceEqual(0, 1, 3, 6, 10, 15, 21, 28, 36, 45); 53 | } 54 | 55 | [Test] 56 | public void PreScanMul() 57 | { 58 | var seq = new[] { 1, 2, 3 }; 59 | var result = seq.PreScan(SampleData.Mul, 1); 60 | result.AssertSequenceEqual(1, 1, 2); 61 | } 62 | 63 | [Test] 64 | public void PreScanFuncIsNotInvokedUnnecessarily() 65 | { 66 | var count = 0; 67 | var gold = new[] { 0, 1, 3 }; 68 | var sequence = Enumerable.Range(1, 3).PreScan((a, b) => 69 | ++count == gold.Length ? throw new TestException() : a + b, 0); 70 | 71 | sequence.AssertSequenceEqual(gold); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /MoreLinq.Test/AssertTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class AssertTest 25 | { 26 | [Test] 27 | public void AssertIsLazy() 28 | { 29 | new BreakingSequence().Assert(BreakingFunc.Of()); 30 | new BreakingSequence().Assert(BreakingFunc.Of(), BreakingFunc.Of()); 31 | } 32 | 33 | [Test] 34 | public void AssertSequenceWithValidAllElements() 35 | { 36 | var source = new[] {2, 4, 6, 8}; 37 | source.Assert(n => n % 2 == 0).AssertSequenceEqual(source); 38 | } 39 | 40 | [Test] 41 | public void AssertSequenceWithValidSomeInvalidElements() 42 | { 43 | Assert.Throws(() => 44 | new[] { 2, 4, 6, 7, 8, 9 }.Assert(n => n % 2 == 0).Consume()); 45 | } 46 | 47 | [Test] 48 | public void AssertSequenceWithInvalidElementsAndCustomErrorReturningNull() 49 | { 50 | Assert.Throws(() => 51 | new[] { 2, 4, 6, 7, 8, 9 }.Assert(n => n % 2 == 0, _ => null).Consume()); 52 | } 53 | 54 | [Test] 55 | public void AssertSequenceWithInvalidElementsAndCustomError() 56 | { 57 | var e = 58 | Assert.Throws(() => 59 | new[] { 2, 4, 6, 7, 8, 9 }.Assert(n => n % 2 == 0, n => new ValueException(n)).Consume()); 60 | Assert.AreEqual(7, e.Value); 61 | } 62 | 63 | class ValueException : Exception 64 | { 65 | public object Value { get; } 66 | public ValueException(object value) { Value = value; } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /MoreLinq.Test/ShuffleTest.cs: -------------------------------------------------------------------------------- 1 | namespace MoreLinq.Test 2 | { 3 | using System; 4 | using NUnit.Framework; 5 | 6 | [TestFixture] 7 | public class ShuffleTest 8 | { 9 | static Random seed = new Random(12345); 10 | 11 | [Test] 12 | public void ShuffleIsLazy() 13 | { 14 | new BreakingSequence().Shuffle(); 15 | } 16 | 17 | [Test] 18 | public void Shuffle() 19 | { 20 | var source = Enumerable.Range(1, 100); 21 | var result = source.Shuffle(); 22 | 23 | Assert.That(result.OrderBy(x => x), Is.EqualTo(source)); 24 | } 25 | 26 | [Test] 27 | public void ShuffleWithEmptySequence() 28 | { 29 | var source = Enumerable.Empty(); 30 | var result = source.Shuffle(); 31 | 32 | Assert.That(result, Is.Empty); 33 | } 34 | 35 | [Test] 36 | public void ShuffleIsIdempotent() 37 | { 38 | var sequence = Enumerable.Range(1, 100).ToArray(); 39 | var sequenceClone = sequence.ToArray(); 40 | 41 | // force complete enumeration of random subsets 42 | sequence.Shuffle().Consume(); 43 | 44 | // verify the original sequence is untouched 45 | Assert.That(sequence, Is.EqualTo(sequenceClone)); 46 | } 47 | 48 | [Test] 49 | public void ShuffleSeedIsLazy() 50 | { 51 | new BreakingSequence().Shuffle(seed); 52 | } 53 | 54 | [Test] 55 | public void ShuffleSeed() 56 | { 57 | var source = Enumerable.Range(1, 100); 58 | var result = source.Shuffle(seed); 59 | 60 | Assert.That(result, Is.Not.EqualTo(source)); 61 | Assert.That(result.OrderBy(x => x), Is.EqualTo(source)); 62 | } 63 | 64 | [Test] 65 | public void ShuffleSeedWithEmptySequence() 66 | { 67 | var source = Enumerable.Empty(); 68 | var result = source.Shuffle(seed); 69 | 70 | Assert.That(result, Is.Empty); 71 | } 72 | 73 | [Test] 74 | public void ShuffleSeedIsIdempotent() 75 | { 76 | var sequence = Enumerable.Range(1, 100).ToArray(); 77 | var sequenceClone = sequence.ToArray(); 78 | 79 | // force complete enumeration of random subsets 80 | sequence.Shuffle(seed).Consume(); 81 | 82 | // verify the original sequence is untouched 83 | Assert.That(sequence, Is.EqualTo(sequenceClone)); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /MoreLinq.Test/ExactlyTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2016 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class ExactlyTest 24 | { 25 | [Test] 26 | public void ExactlyWithNegativeCount() 27 | { 28 | AssertThrowsArgument.OutOfRangeException("count", () => 29 | new[] { 1 }.Exactly(-1)); 30 | } 31 | 32 | [Test] 33 | public void ExactlyWithEmptySequenceHasExactlyZeroElements() 34 | { 35 | foreach (var xs in Enumerable.Empty().ArrangeCollectionTestCases()) 36 | Assert.IsTrue(xs.Exactly(0)); 37 | } 38 | 39 | [Test] 40 | public void ExactlyWithEmptySequenceHasExactlyOneElement() 41 | { 42 | foreach (var xs in Enumerable.Empty().ArrangeCollectionTestCases()) 43 | Assert.IsFalse(xs.Exactly(1)); 44 | } 45 | 46 | [Test] 47 | public void ExactlyWithSingleElementHasExactlyOneElements() 48 | { 49 | foreach (var xs in new[] { 1 }.ArrangeCollectionTestCases()) 50 | Assert.IsTrue(xs.Exactly(1)); 51 | } 52 | 53 | [Test] 54 | public void ExactlyWithManyElementHasExactlyOneElement() 55 | { 56 | foreach (var xs in new[] { 1, 2, 3 }.ArrangeCollectionTestCases()) 57 | Assert.IsFalse(xs.Exactly(1)); 58 | } 59 | 60 | [Test] 61 | public void ExactlyDoesNotIterateUnnecessaryElements() 62 | { 63 | var source = MoreEnumerable.From(() => 1, 64 | () => 2, 65 | () => 3, 66 | () => throw new TestException()); 67 | Assert.IsFalse(source.Exactly(2)); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /MoreLinq/Append.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Returns a sequence consisting of the head elements and the given tail element. 27 | /// 28 | /// Type of sequence 29 | /// All elements of the head. Must not be null. 30 | /// Tail element of the new sequence. 31 | /// A sequence consisting of the head elements and the given tail element. 32 | /// This operator uses deferred execution and streams its results. 33 | 34 | public static IEnumerable Append(this IEnumerable head, T tail) 35 | { 36 | if (head == null) throw new ArgumentNullException(nameof(head)); 37 | return head is PendNode node 38 | ? node.Concat(tail) 39 | : PendNode.WithSource(head).Concat(tail); 40 | } 41 | 42 | /// 43 | /// Returns a sequence consisting of the head elements and the given tail element. 44 | /// 45 | /// Type of sequence 46 | /// All elements of the head. Must not be null. 47 | /// Tail element of the new sequence. 48 | /// A sequence consisting of the head elements and the given tail element. 49 | /// This operator uses deferred execution and streams its results. 50 | 51 | [Obsolete("Use " + nameof(Append) + " instead.")] 52 | public static IEnumerable Concat(this IEnumerable head, T tail) => 53 | head.Append(tail); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /MoreLinq.Test/PadTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class PadTest 24 | { 25 | [Test] 26 | public void PadNegativeWidth() 27 | { 28 | AssertThrowsArgument.Exception("width",() => 29 | new object[0].Pad(-1)); 30 | } 31 | 32 | [Test] 33 | public void PadIsLazy() 34 | { 35 | new BreakingSequence().Pad(0); 36 | } 37 | 38 | [Test] 39 | public void PadWithFillerIsLazy() 40 | { 41 | new BreakingSequence().Pad(0, new object()); 42 | } 43 | 44 | [Test] 45 | public void PadWideSourceSequence() 46 | { 47 | var result = new[] { 123, 456, 789 }.Pad(2); 48 | result.AssertSequenceEqual(123, 456, 789); 49 | } 50 | 51 | [Test] 52 | public void PadEqualSourceSequence() 53 | { 54 | var result = new[] { 123, 456, 789 }.Pad(3); 55 | result.AssertSequenceEqual(123, 456, 789); 56 | } 57 | 58 | [Test] 59 | public void PadNarrowSourceSequenceWithDefaultPadding() 60 | { 61 | var result = new[] { 123, 456, 789 }.Pad(5); 62 | result.AssertSequenceEqual(123, 456, 789, 0, 0); 63 | } 64 | 65 | [Test] 66 | public void PadNarrowSourceSequenceWithNonDefaultPadding() 67 | { 68 | var result = new[] { 123, 456, 789 }.Pad(5, -1); 69 | result.AssertSequenceEqual(123, 456, 789, -1, -1); 70 | } 71 | 72 | [Test] 73 | public void PadNarrowSourceSequenceWithDynamicPadding() 74 | { 75 | var result = "hello".ToCharArray().Pad(15, i => i % 2 == 0 ? '+' : '-'); 76 | result.AssertSequenceEqual("hello-+-+-+-+-+".ToCharArray()); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /MoreLinq/ForEach.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Immediately executes the given action on each element in the source sequence. 27 | /// 28 | /// The type of the elements in the sequence 29 | /// The sequence of elements 30 | /// The action to execute on each element 31 | 32 | public static void ForEach(this IEnumerable source, Action action) 33 | { 34 | if (source == null) throw new ArgumentNullException(nameof(source)); 35 | if (action == null) throw new ArgumentNullException(nameof(action)); 36 | 37 | foreach (var element in source) 38 | action(element); 39 | } 40 | 41 | /// 42 | /// Immediately executes the given action on each element in the source sequence. 43 | /// Each element's index is used in the logic of the action. 44 | /// 45 | /// The type of the elements in the sequence 46 | /// The sequence of elements 47 | /// The action to execute on each element; the second parameter 48 | /// of the action represents the index of the source element. 49 | 50 | public static void ForEach(this IEnumerable source, Action action) 51 | { 52 | if (source == null) throw new ArgumentNullException(nameof(source)); 53 | if (action == null) throw new ArgumentNullException(nameof(action)); 54 | 55 | var index = 0; 56 | foreach (var element in source) 57 | action(element, index++); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /MoreLinq.Test/BacksertTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using NUnit.Framework; 23 | 24 | [TestFixture] 25 | public class BacksertTest 26 | { 27 | [Test] 28 | public void BacksertIsLazy() 29 | { 30 | new BreakingSequence().Backsert(new BreakingSequence(), 0); 31 | } 32 | 33 | [Test] 34 | public void BacksertWithNegativeIndex() 35 | { 36 | AssertThrowsArgument.OutOfRangeException("index", () => 37 | Enumerable.Range(1, 10).Backsert(new[] { 97, 98, 99 }, -1)); 38 | } 39 | 40 | [TestCase(new[] { 1, 2, 3 }, 4, new[] { 9 })] 41 | public void BacksertWithIndexGreaterThanSourceLength(int[] seq1, int index, int[] seq2) 42 | { 43 | using (var test1 = seq1.AsTestingSequence()) 44 | using (var test2 = seq2.AsTestingSequence()) 45 | { 46 | var result = test1.Backsert(test2, index); 47 | 48 | Assert.Throws(() => result.ElementAt(0)); 49 | } 50 | } 51 | 52 | [TestCase(new[] { 1, 2, 3 }, 0, new[] { 8, 9 }, ExpectedResult = new[] { 1, 2, 3, 8, 9 })] 53 | [TestCase(new[] { 1, 2, 3 }, 1, new[] { 8, 9 }, ExpectedResult = new[] { 1, 2, 8, 9, 3 })] 54 | [TestCase(new[] { 1, 2, 3 }, 2, new[] { 8, 9 }, ExpectedResult = new[] { 1, 8, 9, 2, 3 })] 55 | [TestCase(new[] { 1, 2, 3 }, 3, new[] { 8, 9 }, ExpectedResult = new[] { 8, 9, 1, 2, 3 })] 56 | public IEnumerable Backsert(int[] seq1, int index, int[] seq2) 57 | { 58 | using (var test1 = seq1.AsTestingSequence()) 59 | using (var test2 = seq2.AsTestingSequence()) 60 | { 61 | return test1.Backsert(test2, index).ToArray(); 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /MoreLinq/TakeLast.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Linq; 22 | using System.Collections.Generic; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns a specified number of contiguous elements from the end of 28 | /// a sequence. 29 | /// 30 | /// The type of the elements of . 31 | /// The sequence to return the last element of. 32 | /// The number of elements to return. 33 | /// 34 | /// An that contains the specified number of 35 | /// elements from the end of the input sequence. 36 | /// 37 | /// 38 | /// This operator uses deferred execution and streams its results. 39 | /// 40 | /// 41 | /// 45 | /// The result variable, when iterated over, will yield 46 | /// 56 and 78 in turn. 47 | /// 48 | 49 | public static IEnumerable TakeLast(this IEnumerable source, int count) 50 | { 51 | if (source == null) throw new ArgumentNullException(nameof(source)); 52 | 53 | if (count < 1) 54 | return Enumerable.Empty(); 55 | 56 | return 57 | source.TryGetCollectionCount() is int collectionCount 58 | ? source.Slice(Math.Max(0, collectionCount - count), int.MaxValue) 59 | : source.CountDown(count, (e, cd) => (Element: e, Countdown: cd)) 60 | .SkipWhile(e => e.Countdown == null) 61 | .Select(e => e.Element); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /MoreLinq.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.27130.0 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{835F8FFA-471F-4322-B721-A897F27872FA}" 6 | ProjectSection(SolutionItems) = preProject 7 | .editorconfig = .editorconfig 8 | build.cmd = build.cmd 9 | build.sh = build.sh 10 | builddocs.cmd = builddocs.cmd 11 | COPYING.txt = COPYING.txt 12 | global.json = global.json 13 | msbuild.cmd = msbuild.cmd 14 | pack.cmd = pack.cmd 15 | pack.sh = pack.sh 16 | README.md = README.md 17 | test.cmd = test.cmd 18 | test.sh = test.sh 19 | EndProjectSection 20 | EndProject 21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoreLinq", "MoreLinq\MoreLinq.csproj", "{FE8BA6AF-584F-44E0-9F80-2DE800672A87}" 22 | EndProject 23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoreLinq.Test", "MoreLinq.Test\MoreLinq.Test.csproj", "{FE8BA6AF-584F-44E0-9F80-2DE800672A88}" 24 | EndProject 25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoreLinq.ExtensionsGenerator", "bld\ExtensionsGenerator\MoreLinq.ExtensionsGenerator.csproj", "{5FA8F0E8-648A-4C4F-B1BB-B0C46959A36E}" 26 | EndProject 27 | Global 28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 29 | Debug|Any CPU = Debug|Any CPU 30 | Release|Any CPU = Release|Any CPU 31 | EndGlobalSection 32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 33 | {FE8BA6AF-584F-44E0-9F80-2DE800672A87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {FE8BA6AF-584F-44E0-9F80-2DE800672A87}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {FE8BA6AF-584F-44E0-9F80-2DE800672A87}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {FE8BA6AF-584F-44E0-9F80-2DE800672A87}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {FE8BA6AF-584F-44E0-9F80-2DE800672A88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {FE8BA6AF-584F-44E0-9F80-2DE800672A88}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {FE8BA6AF-584F-44E0-9F80-2DE800672A88}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {FE8BA6AF-584F-44E0-9F80-2DE800672A88}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {5FA8F0E8-648A-4C4F-B1BB-B0C46959A36E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {5FA8F0E8-648A-4C4F-B1BB-B0C46959A36E}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {5FA8F0E8-648A-4C4F-B1BB-B0C46959A36E}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {5FA8F0E8-648A-4C4F-B1BB-B0C46959A36E}.Release|Any CPU.Build.0 = Release|Any CPU 45 | EndGlobalSection 46 | GlobalSection(SolutionProperties) = preSolution 47 | HideSolutionNode = FALSE 48 | EndGlobalSection 49 | GlobalSection(ExtensibilityGlobals) = postSolution 50 | SolutionGuid = {6A8EBCB0-B3EB-4D85-AD02-D349122C1D8E} 51 | EndGlobalSection 52 | EndGlobal 53 | -------------------------------------------------------------------------------- /MoreLinq/Index.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2012 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns a sequence of 28 | /// where the key is the zero-based index of the value in the source 29 | /// sequence. 30 | /// 31 | /// Type of elements in sequence. 32 | /// The source sequence. 33 | /// A sequence of . 34 | /// This operator uses deferred execution and streams its 35 | /// results. 36 | 37 | public static IEnumerable> Index(this IEnumerable source) 38 | { 39 | return source.Index(0); 40 | } 41 | 42 | /// 43 | /// Returns a sequence of 44 | /// where the key is the index of the value in the source sequence. 45 | /// An additional parameter specifies the starting index. 46 | /// 47 | /// Type of elements in sequence. 48 | /// The source sequence. 49 | /// 50 | /// A sequence of . 51 | /// This operator uses deferred execution and streams its 52 | /// results. 53 | 54 | public static IEnumerable> Index(this IEnumerable source, int startIndex) 55 | { 56 | if (source == null) throw new ArgumentNullException(nameof(source)); 57 | return source.Select((item, index) => new KeyValuePair(startIndex + index, item)); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /MoreLinq/Exclude.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2010 Leopold Bushkin. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | public static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Excludes a contiguous number of elements from a sequence starting 27 | /// at a given index. 28 | /// 29 | /// The type of the elements of the sequence 30 | /// The sequence to exclude elements from 31 | /// The zero-based index at which to begin excluding elements 32 | /// The number of elements to exclude 33 | /// A sequence that excludes the specified portion of elements 34 | 35 | public static IEnumerable Exclude(this IEnumerable sequence, int startIndex, int count) 36 | { 37 | if (sequence == null) throw new ArgumentNullException(nameof(sequence)); 38 | if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex)); 39 | if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); 40 | 41 | if (count == 0) 42 | return sequence; 43 | 44 | return _(); IEnumerable _() 45 | { 46 | var index = -1; 47 | var endIndex = startIndex + count; 48 | using (var iter = sequence.GetEnumerator()) 49 | { 50 | // yield the first part of the sequence 51 | while (iter.MoveNext() && ++index < startIndex) 52 | yield return iter.Current; 53 | // skip the next part (up to count items) 54 | while (++index < endIndex && iter.MoveNext()) 55 | continue; 56 | // yield the remainder of the sequence 57 | while (iter.MoveNext()) 58 | yield return iter.Current; 59 | } 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /MoreLinq.Test/CountBetweenTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2016 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class CountBetweenTest 24 | { 25 | [Test] 26 | public void CountBetweenWithNegativeMin() 27 | { 28 | AssertThrowsArgument.OutOfRangeException("min", () => 29 | new[] { 1 }.CountBetween(-1, 0)); 30 | } 31 | 32 | [Test] 33 | public void CountBetweenWithNegativeMax() 34 | { 35 | AssertThrowsArgument.OutOfRangeException("max", () => 36 | new[] { 1 }.CountBetween(0, -1)); 37 | } 38 | 39 | [Test] 40 | public void CountBetweenWithMaxLesserThanMin() 41 | { 42 | AssertThrowsArgument.OutOfRangeException("max", () => 43 | new[] { 1 }.CountBetween(1, 0)); 44 | } 45 | 46 | [Test] 47 | public void CountBetweenWithMaxEqualsMin() 48 | { 49 | foreach (var xs in new[] { 1 }.ArrangeCollectionTestCases()) 50 | Assert.IsTrue(xs.CountBetween(1, 1)); 51 | } 52 | 53 | [TestCase(1, 2, 4, false)] 54 | [TestCase(2, 2, 4, true)] 55 | [TestCase(3, 2, 4, true)] 56 | [TestCase(4, 2, 4, true)] 57 | [TestCase(5, 2, 4, false)] 58 | public void CountBetweenRangeTests(int count, int min, int max, bool expecting) 59 | { 60 | foreach (var xs in Enumerable.Range(1, count).ArrangeCollectionTestCases()) 61 | Assert.That(xs.CountBetween(min, max), Is.EqualTo(expecting)); 62 | } 63 | 64 | [Test] 65 | public void CountBetweenDoesNotIterateUnnecessaryElements() 66 | { 67 | var source = MoreEnumerable.From(() => 1, 68 | () => 2, 69 | () => 3, 70 | () => 4, 71 | () => throw new TestException()); 72 | Assert.False(source.CountBetween(2, 3)); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /MoreLinq.Test/ExceptByTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class ExceptByTest 25 | { 26 | [Test] 27 | public void SimpleExceptBy() 28 | { 29 | string[] first = { "aaa", "bb", "c", "dddd" }; 30 | string[] second = { "xx", "y" }; 31 | var result = first.ExceptBy(second, x => x.Length); 32 | result.AssertSequenceEqual("aaa", "dddd"); 33 | } 34 | 35 | [Test] 36 | public void ExceptByIsLazy() 37 | { 38 | var bs = new BreakingSequence(); 39 | bs.ExceptBy(bs, BreakingFunc.Of()); 40 | } 41 | 42 | [Test] 43 | public void ExceptByDoesNotRepeatSourceElementsWithDuplicateKeys() 44 | { 45 | string[] first = { "aaa", "bb", "c", "a", "b", "c", "dddd" }; 46 | string[] second = { "xx" }; 47 | var result = first.ExceptBy(second, x => x.Length); 48 | result.AssertSequenceEqual("aaa", "c", "dddd"); 49 | } 50 | 51 | [Test] 52 | public void ExceptByWithComparer() 53 | { 54 | string[] first = { "first", "second", "third", "fourth" }; 55 | string[] second = { "FIRST" , "thiRD", "FIFTH" }; 56 | var result = first.ExceptBy(second, word => word, StringComparer.OrdinalIgnoreCase); 57 | result.AssertSequenceEqual("second", "fourth"); 58 | } 59 | 60 | [Test] 61 | public void ExceptByNullComparer() 62 | { 63 | string[] first = { "aaa", "bb", "c", "dddd" }; 64 | string[] second = { "xx", "y" }; 65 | var result = first.ExceptBy(second, x => x.Length, null); 66 | result.AssertSequenceEqual("aaa", "dddd"); 67 | } 68 | 69 | [Test] 70 | public void ExceptByIsLazyWithComparer() 71 | { 72 | var bs = new BreakingSequence(); 73 | bs.ExceptBy(bs, BreakingFunc.Of(), StringComparer.Ordinal); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /MoreLinq/Repeat.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2010 Leopold Bushkin. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using Experimental; 23 | 24 | public static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Repeats the sequence the specified number of times. 28 | /// 29 | /// Type of elements in sequence 30 | /// The sequence to repeat 31 | /// Number of times to repeat the sequence 32 | /// A sequence produced from the repetition of the original source sequence 33 | 34 | public static IEnumerable Repeat(this IEnumerable sequence, int count) 35 | { 36 | if (sequence == null) throw new ArgumentNullException(nameof(sequence)); 37 | if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), "Repeat count must be greater than or equal to zero."); 38 | return RepeatImpl(sequence, count); 39 | } 40 | 41 | /// 42 | /// Repeats the sequence forever. 43 | /// 44 | /// Type of elements in sequence 45 | /// The sequence to repeat 46 | /// A sequence produced from the infinite repetition of the original source sequence 47 | 48 | public static IEnumerable Repeat(this IEnumerable sequence) 49 | { 50 | if (sequence == null) throw new ArgumentNullException(nameof(sequence)); 51 | return RepeatImpl(sequence, null); 52 | } 53 | 54 | 55 | static IEnumerable RepeatImpl(IEnumerable sequence, int? count) 56 | { 57 | var memo = sequence.Memoize(); 58 | using (memo as IDisposable) 59 | { 60 | while (count == null || count-- > 0) 61 | { 62 | foreach (var item in memo) 63 | yield return item; 64 | } 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /MoreLinq.Test/AcquireTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class AcquireTest 25 | { 26 | [Test] 27 | public void AcquireAll() 28 | { 29 | Disposable a = null; 30 | Disposable b = null; 31 | Disposable c = null; 32 | 33 | var allocators = MoreEnumerable.From(() => a = new Disposable(), 34 | () => b = new Disposable(), 35 | () => c = new Disposable()); 36 | 37 | var disposables = allocators.Acquire(); 38 | 39 | Assert.That(disposables.Length, Is.EqualTo(3)); 40 | 41 | foreach (var disposable in disposables.ZipShortest(new[] { a, b, c }, (act, exp) => new { Actual = act, Expected = exp })) 42 | { 43 | Assert.That(disposable.Actual, Is.SameAs(disposable.Expected)); 44 | Assert.That(disposable.Actual.Disposed, Is.False); 45 | } 46 | } 47 | 48 | [Test] 49 | public void AcquireSome() 50 | { 51 | Disposable a = null; 52 | Disposable b = null; 53 | Disposable c = null; 54 | 55 | var allocators = MoreEnumerable.From(() => a = new Disposable(), 56 | () => b = new Disposable(), 57 | () => throw new TestException(), 58 | () => c = new Disposable()); 59 | 60 | Assert.Throws(() => allocators.Acquire()); 61 | 62 | Assert.That(a, Is.Not.Null); 63 | Assert.That(a.Disposed, Is.True); 64 | Assert.That(b, Is.Not.Null); 65 | Assert.That(b.Disposed, Is.True); 66 | Assert.That(c, Is.Null); 67 | } 68 | 69 | class Disposable : IDisposable 70 | { 71 | public bool Disposed { get; private set; } 72 | public void Dispose() { Disposed = true; } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /MoreLinq.Test/TakeLastTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | using System.Collections.Generic; 22 | using System; 23 | 24 | [TestFixture] 25 | public class TakeLastTest 26 | { 27 | [Test] 28 | public void TakeLast() 29 | { 30 | AssertTakeLast(new[] { 12, 34, 56, 78, 910, 1112 }, 31 | 3, 32 | result => result.AssertSequenceEqual(78, 910, 1112)); 33 | } 34 | 35 | [Test] 36 | public void TakeLastOnSequenceShortOfCount() 37 | { 38 | AssertTakeLast(new[] { 12, 34, 56 }, 39 | 5, 40 | result => result.AssertSequenceEqual(12, 34, 56)); 41 | } 42 | 43 | [Test] 44 | public void TakeLastWithNegativeCount() 45 | { 46 | AssertTakeLast(new[] { 12, 34, 56 }, 47 | -2, 48 | result => Assert.That(result, Is.Empty)); 49 | } 50 | 51 | [Test] 52 | public void TakeLastIsLazy() 53 | { 54 | new BreakingSequence().TakeLast(1); 55 | } 56 | 57 | [Test] 58 | public void TakeLastDisposesSequenceEnumerator() 59 | { 60 | using (var seq = TestingSequence.Of(1,2,3)) 61 | { 62 | seq.TakeLast(1).Consume(); 63 | } 64 | } 65 | 66 | [TestCase(SourceKind.BreakingList)] 67 | [TestCase(SourceKind.BreakingReadOnlyList)] 68 | public void TakeLastOptimizedForCollections(SourceKind sourceKind) 69 | { 70 | var sequence = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }.ToSourceKind(sourceKind); 71 | 72 | sequence.TakeLast(3).AssertSequenceEqual(8, 9, 10); 73 | } 74 | 75 | static void AssertTakeLast(ICollection input, int count, Action> action) 76 | { 77 | // Test that the behaviour does not change whether a collection 78 | // or a sequence is used as the source. 79 | 80 | action(input.TakeLast(count)); 81 | action(input.Select(x => x).TakeLast(count)); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /MoreLinq/ToHashSet.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | // TODO: Tests! (The code is simple enough I trust it not to fail, mind you...) 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns a of the source items using the default equality 28 | /// comparer for the type. 29 | /// 30 | /// Type of elements in source sequence. 31 | /// Source sequence 32 | /// A hash set of the items in the sequence, using the default equality comparer. 33 | /// is null 34 | /// 35 | /// This evaluates the input sequence completely. 36 | /// 37 | 38 | public static HashSet ToHashSet(this IEnumerable source) 39 | { 40 | return source.ToHashSet(null); 41 | } 42 | 43 | /// 44 | /// Returns a of the source items using the specified equality 45 | /// comparer for the type. 46 | /// 47 | /// Type of elements in source sequence. 48 | /// Source sequence 49 | /// Equality comparer to use; a value of null will cause the type's default equality comparer to be used 50 | /// A hash set of the items in the sequence, using the default equality comparer. 51 | /// is null 52 | /// 53 | /// This evaluates the input sequence completely. 54 | /// 55 | 56 | public static HashSet ToHashSet(this IEnumerable source, IEqualityComparer comparer) 57 | { 58 | if (source == null) throw new ArgumentNullException(nameof(source)); 59 | return new HashSet(source, comparer); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /MoreLinq/Choose.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Applies a function to each element of the source sequence and 28 | /// returns a new sequence of result elements for source elements 29 | /// where the function returns a couple (2-tuple) having a true 30 | /// as its first element and result as the second. 31 | /// 32 | /// 33 | /// The type of the elements in . 34 | /// 35 | /// The type of the elements in the returned sequence. 36 | /// The source sequence. 37 | /// The function that is applied to each source 38 | /// element. 39 | /// A sequence elements. 40 | /// 41 | /// This method uses deferred execution semantics and streams its 42 | /// results. 43 | /// 44 | /// 45 | /// (int.TryParse(s, out var n), n)); 48 | /// ]]> 49 | /// The xs variable will be a sequence of the integers 2, 3, 4, 50 | /// 6, 7 and 9. 51 | /// 52 | 53 | public static IEnumerable Choose(this IEnumerable source, 54 | Func chooser) 55 | { 56 | if (source == null) throw new ArgumentNullException(nameof(source)); 57 | if (chooser == null) throw new ArgumentNullException(nameof(chooser)); 58 | 59 | return _(); IEnumerable _() 60 | { 61 | foreach (var item in source) 62 | { 63 | var (some, value) = chooser(item); 64 | if (some) 65 | yield return value; 66 | } 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /MoreLinq.Test/WindowLeftTest.cs: -------------------------------------------------------------------------------- 1 | namespace MoreLinq.Test 2 | { 3 | using System.Collections.Generic; 4 | using NUnit.Framework; 5 | 6 | [TestFixture] 7 | public class WindowLeftTest 8 | { 9 | [Test] 10 | public void WindowLeftIsLazy() 11 | { 12 | new BreakingSequence().WindowLeft(1); 13 | } 14 | 15 | [Test] 16 | public void WindowLeftWithNegativeWindowSize() 17 | { 18 | AssertThrowsArgument.OutOfRangeException("size", () => 19 | Enumerable.Repeat(1, 10).WindowLeft(-5)); 20 | } 21 | 22 | [Test] 23 | public void WindowLeftWithEmptySequence() 24 | { 25 | using (var xs = Enumerable.Empty().AsTestingSequence()) 26 | { 27 | var result = xs.WindowLeft(5); 28 | Assert.That(result, Is.Empty); 29 | } 30 | } 31 | 32 | [Test] 33 | public void WindowLeftWithSingleElement() 34 | { 35 | const int count = 100; 36 | var sequence = Enumerable.Range(1, count).ToArray(); 37 | 38 | IList[] result; 39 | using (var ts = sequence.AsTestingSequence()) 40 | result = ts.WindowLeft(1).ToArray(); 41 | 42 | // number of windows should be equal to the source sequence length 43 | Assert.That(result.Length, Is.EqualTo(count)); 44 | 45 | // each window should contain single item consistent of element at that offset 46 | foreach (var window in result.Index()) 47 | Assert.That(sequence.ElementAt(window.Key), Is.EqualTo(window.Value.Single())); 48 | } 49 | 50 | [Test] 51 | public void WindowLeftWithWindowSizeLargerThanSequence() 52 | { 53 | using (var sequence = Enumerable.Range(1, 5).AsTestingSequence()) 54 | using (var reader = sequence.WindowLeft(10).Read()) 55 | { 56 | reader.Read().AssertSequenceEqual(1, 2, 3, 4, 5); 57 | reader.Read().AssertSequenceEqual(2, 3, 4, 5); 58 | reader.Read().AssertSequenceEqual(3, 4, 5); 59 | reader.Read().AssertSequenceEqual(4, 5); 60 | reader.Read().AssertSequenceEqual(5); 61 | reader.ReadEnd(); 62 | } 63 | } 64 | 65 | [Test] 66 | public void WindowLeftWithWindowSizeSmallerThanSequence() 67 | { 68 | using (var sequence = Enumerable.Range(1, 5).AsTestingSequence()) 69 | using (var reader = sequence.WindowLeft(3).Read()) 70 | { 71 | reader.Read().AssertSequenceEqual(1, 2, 3); 72 | reader.Read().AssertSequenceEqual(2, 3, 4); 73 | reader.Read().AssertSequenceEqual(3, 4, 5); 74 | reader.Read().AssertSequenceEqual(4, 5); 75 | reader.Read().AssertSequenceEqual(5); 76 | reader.ReadEnd(); 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /MoreLinq.Test/ScanTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class ScanTest 25 | { 26 | [Test] 27 | public void ScanEmpty() 28 | { 29 | Assert.That(new int[0].Scan(SampleData.Plus), Is.Empty); 30 | } 31 | 32 | [Test] 33 | public void ScanSum() 34 | { 35 | var result = Enumerable.Range(1, 10).Scan(SampleData.Plus); 36 | var gold = new[] { 1, 3, 6, 10, 15, 21, 28, 36, 45, 55 }; 37 | result.AssertSequenceEqual(gold); 38 | } 39 | 40 | [Test] 41 | public void ScanIsLazy() 42 | { 43 | new BreakingSequence().Scan(BreakingFunc.Of()); 44 | } 45 | 46 | [Test] 47 | public void ScanDoesNotIterateExtra() 48 | { 49 | var sequence = Enumerable.Range(1, 3).Concat(new BreakingSequence()).Scan(SampleData.Plus); 50 | var gold = new[] {1, 3, 6}; 51 | Assert.Throws(sequence.Consume); 52 | sequence.Take(3).AssertSequenceEqual(gold); 53 | } 54 | 55 | [Test] 56 | public void SeededScanEmpty() 57 | { 58 | Assert.AreEqual(-1, new int[0].Scan(-1, SampleData.Plus).Single()); 59 | } 60 | 61 | [Test] 62 | public void SeededScanSum() 63 | { 64 | var result = Enumerable.Range(1, 10).Scan(0, SampleData.Plus); 65 | var gold = new[] { 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55 }; 66 | result.AssertSequenceEqual(gold); 67 | } 68 | 69 | [Test] 70 | public void SeededScanIsLazy() 71 | { 72 | new BreakingSequence().Scan(null, BreakingFunc.Of()); 73 | } 74 | 75 | [Test] 76 | public void SeededScanDoesNotIterateExtra() 77 | { 78 | var sequence = Enumerable.Range(1, 3).Concat(new BreakingSequence()).Scan(0, SampleData.Plus); 79 | var gold = new[] { 0, 1, 3, 6 }; 80 | Assert.Throws(sequence.Consume); 81 | sequence.Take(4).AssertSequenceEqual(gold); 82 | } 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /MoreLinq.Test/WindowRightTest.cs: -------------------------------------------------------------------------------- 1 | namespace MoreLinq.Test 2 | { 3 | using System.Collections.Generic; 4 | using NUnit.Framework; 5 | 6 | [TestFixture] 7 | public class WindowRightTest 8 | { 9 | [Test] 10 | public void WindowRightIsLazy() 11 | { 12 | new BreakingSequence().WindowRight(1); 13 | } 14 | 15 | [Test] 16 | public void WindowRightWithNegativeWindowSize() 17 | { 18 | AssertThrowsArgument.OutOfRangeException("size", () => 19 | Enumerable.Repeat(1, 10).WindowRight(-5)); 20 | } 21 | 22 | [Test] 23 | public void WindowRightWithEmptySequence() 24 | { 25 | using (var xs = Enumerable.Empty().AsTestingSequence()) 26 | { 27 | var result = xs.WindowRight(5); 28 | Assert.That(result, Is.Empty); 29 | } 30 | } 31 | 32 | [Test] 33 | public void WindowRightWithSingleElement() 34 | { 35 | const int count = 100; 36 | var sequence = Enumerable.Range(1, count).ToArray(); 37 | 38 | IList[] result; 39 | using (var ts = sequence.AsTestingSequence()) 40 | result = ts.WindowRight(1).ToArray(); 41 | 42 | // number of windows should be equal to the source sequence length 43 | Assert.That(result.Length, Is.EqualTo(count)); 44 | 45 | // each window should contain single item consistent of element at that offset 46 | foreach (var window in result.Index()) 47 | Assert.That(sequence.ElementAt(window.Key), Is.EqualTo(window.Value.Single())); 48 | } 49 | 50 | [Test] 51 | public void WindowRightWithWindowSizeLargerThanSequence() 52 | { 53 | using (var sequence = Enumerable.Range(1, 5).AsTestingSequence()) 54 | using (var reader = sequence.WindowRight(10).Read()) 55 | { 56 | reader.Read().AssertSequenceEqual( 1); 57 | reader.Read().AssertSequenceEqual( 1, 2); 58 | reader.Read().AssertSequenceEqual( 1, 2, 3); 59 | reader.Read().AssertSequenceEqual( 1, 2, 3, 4); 60 | reader.Read().AssertSequenceEqual(1, 2, 3, 4, 5); 61 | reader.ReadEnd(); 62 | } 63 | } 64 | 65 | [Test] 66 | public void WindowRightWithWindowSizeSmallerThanSequence() 67 | { 68 | using (var sequence = Enumerable.Range(1, 5).AsTestingSequence()) 69 | using (var reader = sequence.WindowRight(3).Read()) 70 | { 71 | reader.Read().AssertSequenceEqual( 1); 72 | reader.Read().AssertSequenceEqual( 1, 2); 73 | reader.Read().AssertSequenceEqual(1, 2, 3); 74 | reader.Read().AssertSequenceEqual(2, 3, 4); 75 | reader.Read().AssertSequenceEqual(3, 4, 5); 76 | reader.ReadEnd(); 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /MoreLinq/SequenceException.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | #if !NO_EXCEPTION_SERIALIZATION 22 | using System.Runtime.Serialization; 23 | #endif 24 | 25 | /// 26 | /// The exception that is thrown for a sequence that fails a condition. 27 | /// 28 | 29 | #if !NO_EXCEPTION_SERIALIZATION 30 | [ Serializable ] 31 | #endif 32 | public class SequenceException : Exception 33 | { 34 | const string DefaultMessage = "Error in sequence."; 35 | 36 | /// 37 | /// Initializes a new instance of the class. 38 | /// 39 | 40 | public SequenceException() : 41 | this(null) {} 42 | 43 | /// 44 | /// Initializes a new instance of the class 45 | /// with a given error message. 46 | /// 47 | /// A message that describes the error. 48 | 49 | public SequenceException(string message) : 50 | this(message, null) { } 51 | 52 | /// 53 | /// Initializes a new instance of the class 54 | /// with a given error message and a reference to the inner exception 55 | /// that is the cause of the exception. 56 | /// 57 | /// A message that describes the error. 58 | /// The exception that is the cause of the current exception. 59 | 60 | public SequenceException(string message, Exception innerException) : 61 | base(string.IsNullOrEmpty(message) ? DefaultMessage : message, innerException) { } 62 | 63 | #if !NO_EXCEPTION_SERIALIZATION 64 | /// 65 | /// Initializes a new instance of the class 66 | /// with serialized data. 67 | /// 68 | /// The object that holds the serialized object data. 69 | /// The contextual information about the source or destination. 70 | 71 | protected SequenceException(SerializationInfo info, StreamingContext context) : 72 | base(info, context) {} 73 | #endif 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /MoreLinq.Test/AtMostTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2016 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class AtMostTest 24 | { 25 | [Test] 26 | public void AtMostWithNegativeCount() 27 | { 28 | AssertThrowsArgument.OutOfRangeException("count", 29 | () => new[] { 1 }.AtMost(-1)); 30 | } 31 | 32 | [Test] 33 | public void AtMostWithEmptySequenceHasAtMostZeroElements() 34 | { 35 | foreach (var xs in Enumerable.Empty().ArrangeCollectionTestCases()) 36 | Assert.IsTrue(xs.AtMost(0)); 37 | } 38 | 39 | [Test] 40 | public void AtMostWithEmptySequenceHasAtMostOneElement() 41 | { 42 | foreach (var xs in Enumerable.Empty().ArrangeCollectionTestCases()) 43 | Assert.IsTrue(xs.AtMost(1)); 44 | } 45 | 46 | [Test] 47 | public void AtMostWithSingleElementHasAtMostZeroElements() 48 | { 49 | foreach (var xs in new[] { 1 }.ArrangeCollectionTestCases()) 50 | Assert.IsFalse(xs.AtMost(0)); 51 | } 52 | 53 | [Test] 54 | public void AtMostWithSingleElementHasAtMostOneElement() 55 | { 56 | foreach (var xs in new[] { 1 }.ArrangeCollectionTestCases()) 57 | Assert.IsTrue(xs.AtMost(1)); 58 | } 59 | 60 | [Test] 61 | public void AtMostWithSingleElementHasAtMostManyElements() 62 | { 63 | foreach (var xs in new[] { 1 }.ArrangeCollectionTestCases()) 64 | Assert.IsTrue(xs.AtMost(2)); 65 | } 66 | 67 | [Test] 68 | public void AtMostWithManyElementsHasAtMostOneElements() 69 | { 70 | foreach (var xs in new[] { 1, 2, 3 }.ArrangeCollectionTestCases()) 71 | Assert.IsFalse(xs.AtMost(1)); 72 | } 73 | 74 | [Test] 75 | public void AtMostDoesNotIterateUnnecessaryElements() 76 | { 77 | var source = MoreEnumerable.From(() => 1, 78 | () => 2, 79 | () => 3, 80 | () => throw new TestException()); 81 | Assert.IsFalse(source.AtMost(2)); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /MoreLinq/ToDelimitedString.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2009 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Diagnostics; 23 | using System.Text; 24 | 25 | static partial class MoreEnumerable 26 | { 27 | /// 28 | /// Creates a delimited string from a sequence of values and 29 | /// a given delimiter. 30 | /// 31 | /// Type of element in the source sequence 32 | /// The sequence of items to delimit. Each is converted to a string using the 33 | /// simple ToString() conversion. 34 | /// The delimiter to inject between elements. 35 | /// 36 | /// A string that consists of the elements in 37 | /// delimited by . If the source sequence 38 | /// is empty, the method returns an empty string. 39 | /// 40 | /// 41 | /// or is null. 42 | /// 43 | /// 44 | /// This operator uses immediate execution and effectively buffers the sequence. 45 | /// 46 | 47 | public static string ToDelimitedString(this IEnumerable source, string delimiter) 48 | { 49 | if (source == null) throw new ArgumentNullException(nameof(source)); 50 | if (delimiter == null) throw new ArgumentNullException(nameof(delimiter)); 51 | return ToDelimitedStringImpl(source, delimiter, (sb, e) => sb.Append(e)); 52 | } 53 | 54 | static string ToDelimitedStringImpl(IEnumerable source, string delimiter, Func append) 55 | { 56 | Debug.Assert(source != null); 57 | Debug.Assert(delimiter != null); 58 | Debug.Assert(append != null); 59 | 60 | var sb = new StringBuilder(); 61 | var i = 0; 62 | 63 | foreach (var value in source) 64 | { 65 | if (i++ > 0) sb.Append(delimiter); 66 | append(sb, value); 67 | } 68 | 69 | return sb.ToString(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /MoreLinq/Fold.g.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="false" language="C#" #> 2 | <#@ output extension=".cs" #> 3 | <#@ assembly name="System.Core" #> 4 | <#@ import namespace="System.Globalization" #> 5 | <#@ import namespace="System.Linq" #> 6 | #region License and Terms 7 | // MoreLINQ - Extensions to LINQ to Objects 8 | // Copyright (c) 2013 Atif Aziz. All rights reserved. 9 | // 10 | // Licensed under the Apache License, Version 2.0 (the "License"); 11 | // you may not use this file except in compliance with the License. 12 | // You may obtain a copy of the License at 13 | // 14 | // http://www.apache.org/licenses/LICENSE-2.0 15 | // 16 | // Unless required by applicable law or agreed to in writing, software 17 | // distributed under the License is distributed on an "AS IS" BASIS, 18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | // See the License for the specific language governing permissions and 20 | // limitations under the License. 21 | #endregion 22 | 23 | namespace MoreLinq 24 | { 25 | using System; 26 | using System.Collections.Generic; 27 | 28 | partial class MoreEnumerable 29 | { 30 | <# const int max = 16; 31 | var overloads = 32 | from i in Enumerable.Range(1, max) 33 | let istr = i.ToString(CultureInfo.InvariantCulture) 34 | select new 35 | { 36 | Ts = string.Join(", ", Enumerable.Repeat("T", i)), 37 | Count = i, 38 | CountElements = istr + " " + (i == 1 ? "element" : "elements"), 39 | CountArg = istr, 40 | FolderArgs = "folder" + istr + ": folder", 41 | 42 | }; 43 | 44 | foreach (var e in overloads) { #> 45 | /// 46 | /// Returns the result of applying a function to a sequence of 47 | /// <#= e.CountElements #>. 48 | /// 49 | /// 50 | /// This operator uses immediate execution and effectively buffers 51 | /// as many items of the source sequence as necessary. 52 | /// 53 | /// Type of element in the source sequence 54 | /// Type of the result 55 | /// The sequence of items to fold. 56 | /// Function to apply to the elements in the sequence. 57 | /// The folded value returned by . 58 | /// is null 59 | /// is null 60 | /// does not contain exactly <#= e.CountElements #> 61 | 62 | public static TResult Fold(this IEnumerable source, Func<<#= e.Ts #>, TResult> folder) 63 | { 64 | return FoldImpl(source, <#= e.CountArg #>, <#= e.FolderArgs #>); 65 | } 66 | 67 | <# } #> 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /MoreLinq.Test/ChooseTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Globalization; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class ChooseTest 25 | { 26 | [Test] 27 | public void IsLazy() 28 | { 29 | new BreakingSequence() 30 | .Choose(BreakingFunc.Of()); 31 | } 32 | 33 | [Test] 34 | public void WithEmptySource() 35 | { 36 | using (var xs = Enumerable.Empty().AsTestingSequence()) 37 | Assert.That(xs.Choose(BreakingFunc.Of()), Is.Empty); 38 | } 39 | 40 | [Test] 41 | public void None() 42 | { 43 | using (var xs = Enumerable.Range(1, 10).AsTestingSequence()) 44 | Assert.That(xs.Choose(_ => (false, 0)), Is.Empty); 45 | } 46 | 47 | [Test] 48 | public void ThoseParsable() 49 | { 50 | using (var xs = 51 | "O,l,2,3,4,S,6,7,B,9" 52 | .Split(',') 53 | .Choose(s => (int.TryParse(s, NumberStyles.Integer, 54 | CultureInfo.InvariantCulture, 55 | out var n), n)) 56 | .AsTestingSequence()) 57 | { 58 | xs.AssertSequenceEqual(2, 3, 4, 6, 7, 9); 59 | } 60 | } 61 | 62 | // A cheap trick to masquerade a tuple as an option 63 | 64 | static class Option 65 | { 66 | public static (bool IsSome, T Value) Some(T value) => (true, value); 67 | } 68 | 69 | static class Option 70 | { 71 | public static readonly (bool IsSome, T Value) None = (false, default); 72 | } 73 | 74 | [Test] 75 | public void ThoseThatAreIntegers() 76 | { 77 | new int?[] { 0, 1, 2, null, 4, null, 6, null, null, 9 } 78 | .Choose(e => e is int n ? Option.Some(n) : Option.None) 79 | .AssertSequenceEqual(0, 1, 2, 4, 6, 9); 80 | } 81 | 82 | [Test] 83 | public void ThoseEven() 84 | { 85 | Enumerable.Range(1, 10) 86 | .Choose(x => x % 2 is 0 ? Option.Some(x) : Option.None) 87 | .AssertSequenceEqual(2, 4, 6, 8, 10); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /MoreLinq/TagFirstLast.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2013 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns a sequence resulting from applying a function to each 28 | /// element in the source sequence with additional parameters 29 | /// indicating whether the element is the first and/or last of the 30 | /// sequence. 31 | /// 32 | /// The type of the elements of . 33 | /// The type of the element of the returned sequence. 34 | /// The source sequence. 35 | /// A function that determines how to 36 | /// project the each element along with its first or last tag. 37 | /// 38 | /// Returns the resulting sequence. 39 | /// 40 | /// 41 | /// This operator uses deferred execution and streams its results. 42 | /// 43 | /// 44 | /// new 47 | /// { 48 | /// Number = num, 49 | /// IsFirst = fst, IsLast = lst 50 | /// }); 51 | /// ]]> 52 | /// The result variable, when iterated over, will yield 53 | /// { Number = 123, IsFirst = True, IsLast = False }, 54 | /// { Number = 456, IsFirst = False, IsLast = False } and 55 | /// { Number = 789, IsFirst = False, IsLast = True } in turn. 56 | /// 57 | 58 | public static IEnumerable TagFirstLast(this IEnumerable source, Func resultSelector) 59 | { 60 | if (source == null) throw new ArgumentNullException(nameof(source)); 61 | if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); 62 | 63 | return source.Index() // count-up 64 | .CountDown(1, (e, cd) => resultSelector(e.Value, e.Key == 0, cd == 0)); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /MoreLinq/Pairwise.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2012 Atif Aziz. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | 23 | static partial class MoreEnumerable 24 | { 25 | /// 26 | /// Returns a sequence resulting from applying a function to each 27 | /// element in the source sequence and its 28 | /// predecessor, with the exception of the first element which is 29 | /// only returned as the predecessor of the second element. 30 | /// 31 | /// The type of the elements of . 32 | /// The type of the element of the returned sequence. 33 | /// The source sequence. 34 | /// A transform function to apply to 35 | /// each pair of sequence. 36 | /// 37 | /// Returns the resulting sequence. 38 | /// 39 | /// 40 | /// This operator uses deferred execution and streams its results. 41 | /// 42 | /// 43 | /// a + b); 46 | /// ]]> 47 | /// The result variable, when iterated over, will yield 48 | /// "ab", "bc" and "cd", in turn. 49 | /// 50 | 51 | public static IEnumerable Pairwise(this IEnumerable source, Func resultSelector) 52 | { 53 | if (source == null) throw new ArgumentNullException(nameof(source)); 54 | if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); 55 | 56 | return _(); IEnumerable _() 57 | { 58 | using (var e = source.GetEnumerator()) 59 | { 60 | if (!e.MoveNext()) 61 | yield break; 62 | 63 | var previous = e.Current; 64 | while (e.MoveNext()) 65 | { 66 | yield return resultSelector(previous, e.Current); 67 | previous = e.Current; 68 | } 69 | } 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /MoreLinq.Test/FallbackIfEmptyTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class FallbackIfEmptyTest 24 | { 25 | [Test] 26 | public void FallbackIfEmptyWithEmptySequence() 27 | { 28 | var source = Enumerable.Empty().Select(x => x); 29 | // ReSharper disable PossibleMultipleEnumeration 30 | source.FallbackIfEmpty(12).AssertSequenceEqual(12); 31 | source.FallbackIfEmpty(12, 23).AssertSequenceEqual(12, 23); 32 | source.FallbackIfEmpty(12, 23, 34).AssertSequenceEqual(12, 23, 34); 33 | source.FallbackIfEmpty(12, 23, 34, 45).AssertSequenceEqual(12, 23, 34, 45); 34 | source.FallbackIfEmpty(12, 23, 34, 45, 56).AssertSequenceEqual(12, 23, 34, 45, 56); 35 | source.FallbackIfEmpty(12, 23, 34, 45, 56, 67).AssertSequenceEqual(12, 23, 34, 45, 56, 67); 36 | // ReSharper restore PossibleMultipleEnumeration 37 | } 38 | 39 | [TestCase(SourceKind.BreakingCollection)] 40 | [TestCase(SourceKind.BreakingReadOnlyCollection)] 41 | public void FallbackIfEmptyPreservesSourceCollectionIfPossible(SourceKind sourceKind) 42 | { 43 | var source = new[] { 1 }.ToSourceKind(sourceKind); 44 | // ReSharper disable PossibleMultipleEnumeration 45 | Assert.AreSame(source.FallbackIfEmpty(12), source); 46 | Assert.AreSame(source.FallbackIfEmpty(12, 23), source); 47 | Assert.AreSame(source.FallbackIfEmpty(12, 23, 34), source); 48 | Assert.AreSame(source.FallbackIfEmpty(12, 23, 34, 45), source); 49 | Assert.AreSame(source.FallbackIfEmpty(12, 23, 34, 45, 56), source); 50 | Assert.AreSame(source.FallbackIfEmpty(12, 23, 34, 45, 56, 67), source); 51 | // ReSharper restore PossibleMultipleEnumeration 52 | } 53 | 54 | [TestCase(SourceKind.BreakingCollection)] 55 | [TestCase(SourceKind.BreakingReadOnlyCollection)] 56 | public void FallbackIfEmptyPreservesFallbackCollectionIfPossible(SourceKind sourceKind) 57 | { 58 | var source = new int[0].ToSourceKind(sourceKind); 59 | var fallback = new[] { 1 }; 60 | Assert.AreSame(source.FallbackIfEmpty(fallback), fallback); 61 | Assert.AreSame(source.FallbackIfEmpty(fallback.AsEnumerable()), fallback); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /MoreLinq.Test/TestingSequence.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using System.Collections; 22 | using System.Collections.Generic; 23 | using NUnit.Framework; 24 | 25 | static class TestingSequence 26 | { 27 | internal static TestingSequence Of(params T[] elements) => 28 | new TestingSequence(elements); 29 | 30 | internal static TestingSequence AsTestingSequence(this IEnumerable source) => 31 | source != null 32 | ? new TestingSequence(source) 33 | : throw new ArgumentNullException(nameof(source)); 34 | } 35 | 36 | /// 37 | /// Sequence that asserts whether its iterator has been disposed 38 | /// when it is disposed itself and also whether GetEnumerator() is 39 | /// called exactly once or not. 40 | /// 41 | sealed class TestingSequence : IEnumerable, IDisposable 42 | { 43 | bool? _disposed; 44 | IEnumerable _sequence; 45 | 46 | internal TestingSequence(IEnumerable sequence) => 47 | _sequence = sequence; 48 | 49 | public int MoveNextCallCount { get; private set; } 50 | 51 | void IDisposable.Dispose() => 52 | AssertDisposed(); 53 | 54 | /// 55 | /// Checks that the iterator was disposed, and then resets. 56 | /// 57 | void AssertDisposed() 58 | { 59 | if (_disposed == null) 60 | return; 61 | Assert.IsTrue(_disposed, "Expected sequence to be disposed."); 62 | _disposed = null; 63 | } 64 | 65 | public IEnumerator GetEnumerator() 66 | { 67 | Assert.That(_sequence, Is.Not.Null, "LINQ operators should not enumerate a sequence more than once."); 68 | var enumerator = _sequence.GetEnumerator().AsWatchtable(); 69 | _disposed = false; 70 | enumerator.Disposed += delegate 71 | { 72 | Assert.That(_disposed, Is.False, "LINQ operators should not dispose a sequence more than once."); 73 | _disposed = true; 74 | }; 75 | enumerator.MoveNextCalled += delegate { MoveNextCallCount++; }; 76 | _sequence = null; 77 | return enumerator; 78 | } 79 | 80 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 81 | 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /MoreLinq.Test/ToDictionaryTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class ToDictionaryTest 25 | { 26 | [Test] 27 | public void ToDictionaryWithKeyValuePairs() 28 | { 29 | var pairs = new[] 30 | { 31 | KeyValuePair.Create("foo", 123), 32 | KeyValuePair.Create("bar", 456), 33 | KeyValuePair.Create("baz", 789), 34 | }; 35 | 36 | var dict = pairs.ToDictionary(); 37 | 38 | Assert.That(dict["foo"], Is.EqualTo(123)); 39 | Assert.That(dict["bar"], Is.EqualTo(456)); 40 | Assert.That(dict["baz"], Is.EqualTo(789)); 41 | } 42 | 43 | [Test] 44 | public void ToDictionaryWithCouples() 45 | { 46 | var pairs = new[] 47 | { 48 | ("foo", 123), 49 | ("bar", 456), 50 | ("baz", 789), 51 | }; 52 | 53 | var dict = pairs.ToDictionary(); 54 | 55 | Assert.That(dict["foo"], Is.EqualTo(123)); 56 | Assert.That(dict["bar"], Is.EqualTo(456)); 57 | Assert.That(dict["baz"], Is.EqualTo(789)); 58 | } 59 | 60 | [Test] 61 | public void ToDictionaryWithKeyValuePairsWithComparer() 62 | { 63 | var pairs = new[] 64 | { 65 | KeyValuePair.Create("foo", 123), 66 | KeyValuePair.Create("bar", 456), 67 | KeyValuePair.Create("baz", 789), 68 | }; 69 | 70 | var dict = pairs.ToDictionary(StringComparer.OrdinalIgnoreCase); 71 | 72 | Assert.That(dict["FOO"], Is.EqualTo(123)); 73 | Assert.That(dict["BAR"], Is.EqualTo(456)); 74 | Assert.That(dict["BAZ"], Is.EqualTo(789)); 75 | } 76 | 77 | [Test] 78 | public void ToDictionaryWithCouplesWithComparer() 79 | { 80 | var pairs = new[] 81 | { 82 | ("foo", 123), 83 | ("bar", 456), 84 | ("baz", 789), 85 | }; 86 | 87 | var dict = pairs.ToDictionary(StringComparer.OrdinalIgnoreCase); 88 | 89 | Assert.That(dict["FOO"], Is.EqualTo(123)); 90 | Assert.That(dict["BAR"], Is.EqualTo(456)); 91 | Assert.That(dict["BAZ"], Is.EqualTo(789)); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /MoreLinq/Slice.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2010 Leopold Bushkin. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | public static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Extracts a contiguous count of elements from a sequence at a particular zero-based starting index 28 | /// 29 | /// 30 | /// If the starting position or count specified result in slice extending past the end of the sequence, 31 | /// it will return all elements up to that point. There is no guarantee that the resulting sequence will 32 | /// contain the number of elements requested - it may have anywhere from 0 to .
33 | /// This method is implemented in an optimized manner for any sequence implementing IList{T}.
34 | /// The result of Slice() is identical to: sequence.Skip(startIndex).Take(count) 35 | ///
36 | /// The type of the elements in the source sequence 37 | /// The sequence from which to extract elements 38 | /// The zero-based index at which to begin slicing 39 | /// The number of items to slice out of the index 40 | /// A new sequence containing any elements sliced out from the source sequence 41 | 42 | public static IEnumerable Slice(this IEnumerable sequence, int startIndex, int count) 43 | { 44 | if (sequence == null) throw new ArgumentNullException(nameof(sequence)); 45 | if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex)); 46 | if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); 47 | 48 | return sequence is IList list ? SliceList(list.Count, i => list[i]) 49 | : sequence is IReadOnlyList readOnlyList ? SliceList(readOnlyList.Count, i => readOnlyList[i]) 50 | : sequence.Skip(startIndex).Take(count); 51 | 52 | IEnumerable SliceList(int listCount, Func indexer) 53 | { 54 | var countdown = count; 55 | var index = startIndex; 56 | while (index < listCount && countdown-- > 0) 57 | yield return indexer(index++); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /MoreLinq.Test/BatchTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class BatchTest 25 | { 26 | [Test] 27 | public void BatchZeroSize() 28 | { 29 | AssertThrowsArgument.OutOfRangeException("size",() => 30 | new object[0].Batch(0)); 31 | } 32 | 33 | [Test] 34 | public void BatchNegativeSize() 35 | { 36 | AssertThrowsArgument.OutOfRangeException("size",() => 37 | new object[0].Batch(-1)); 38 | } 39 | 40 | [Test] 41 | public void BatchEvenlyDivisibleSequence() 42 | { 43 | var result = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }.Batch(3); 44 | using (var reader = result.Read()) 45 | { 46 | reader.Read().AssertSequenceEqual(1, 2, 3); 47 | reader.Read().AssertSequenceEqual(4, 5, 6); 48 | reader.Read().AssertSequenceEqual(7, 8, 9); 49 | reader.ReadEnd(); 50 | } 51 | } 52 | 53 | [Test] 54 | public void BatchUnevenlyDivisbleSequence() 55 | { 56 | var result = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }.Batch(4); 57 | using (var reader = result.Read()) 58 | { 59 | reader.Read().AssertSequenceEqual(1, 2, 3, 4); 60 | reader.Read().AssertSequenceEqual(5, 6, 7, 8); 61 | reader.Read().AssertSequenceEqual(9); 62 | reader.ReadEnd(); 63 | } 64 | } 65 | 66 | [Test] 67 | public void BatchSequenceTransformingResult() 68 | { 69 | var result = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }.Batch(4, batch => batch.Sum()); 70 | result.AssertSequenceEqual(10, 26, 9); 71 | } 72 | 73 | [Test] 74 | public void BatchSequenceYieldsListsOfBatches() 75 | { 76 | var result = new[] { 1, 2, 3 }.Batch(2); 77 | using (var reader = result.Read()) 78 | { 79 | Assert.That(reader.Read(), Is.InstanceOf(typeof(IList))); 80 | Assert.That(reader.Read(), Is.InstanceOf(typeof(IList))); 81 | reader.ReadEnd(); 82 | } 83 | } 84 | 85 | [Test] 86 | public void BatchIsLazy() 87 | { 88 | new BreakingSequence().Batch(1); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /MoreLinq/Shuffle.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | public static partial class MoreEnumerable 25 | { 26 | /// 27 | /// Returns a sequence of elements in random order from the original 28 | /// sequence. 29 | /// 30 | /// The type of source sequence elements. 31 | /// 32 | /// The sequence from which to return random elements. 33 | /// 34 | /// A sequence of elements randomized in 35 | /// their order. 36 | /// 37 | /// 38 | /// This method uses deferred execution and streams its results. The 39 | /// source sequence is entirely buffered before the results are 40 | /// streamed. 41 | /// 42 | 43 | public static IEnumerable Shuffle(this IEnumerable source) 44 | { 45 | return Shuffle(source, new Random()); 46 | } 47 | 48 | /// 49 | /// Returns a sequence of elements in random order from the original 50 | /// sequence. An additional parameter specifies a random generator to be 51 | /// used for the random selection algorithm. 52 | /// 53 | /// The type of source sequence elements. 54 | /// 55 | /// The sequence from which to return random elements. 56 | /// 57 | /// A random generator used as part of the selection algorithm. 58 | /// 59 | /// A sequence of elements randomized in 60 | /// their order. 61 | /// 62 | /// 63 | /// This method uses deferred execution and streams its results. The 64 | /// source sequence is entirely buffered before the results are 65 | /// streamed. 66 | /// 67 | 68 | public static IEnumerable Shuffle(this IEnumerable source, Random rand) 69 | { 70 | if (source == null) throw new ArgumentNullException(nameof(source)); 71 | if (rand == null) throw new ArgumentNullException(nameof(rand)); 72 | 73 | return RandomSubsetImpl(source, rand, seq => 74 | { 75 | var array = seq.ToArray(); 76 | return (array, array.Length); 77 | }); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /MoreLinq.Test/InsertTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class InsertTest 24 | { 25 | [Test] 26 | public void InsertWithNegativeIndex() 27 | { 28 | AssertThrowsArgument.OutOfRangeException("index", () => 29 | Enumerable.Range(1, 10).Insert(new[] { 97, 98, 99 }, -1)); 30 | } 31 | 32 | [TestCase(7)] 33 | [TestCase(8)] 34 | [TestCase(9)] 35 | public void InsertWithIndexGreaterThanSourceLengthMaterialized(int count) 36 | { 37 | var seq1 = Enumerable.Range(0, count).ToList(); 38 | var seq2 = new[] { 97, 98, 99 }; 39 | 40 | using (var test1 = seq1.AsTestingSequence()) 41 | using (var test2 = seq2.AsTestingSequence()) 42 | { 43 | var result = test1.Insert(test2, count + 1); 44 | 45 | AssertThrowsArgument.OutOfRangeException("index", () => 46 | result.ForEach((e, index) => 47 | Assert.That(e, Is.EqualTo(seq1[index])))); 48 | } 49 | } 50 | 51 | [TestCase(7)] 52 | [TestCase(8)] 53 | [TestCase(9)] 54 | public void InsertWithIndexGreaterThanSourceLengthLazy(int count) 55 | { 56 | var seq1 = Enumerable.Range(0, count); 57 | var seq2 = new[] { 97, 98, 99 }; 58 | 59 | using (var test1 = seq1.AsTestingSequence()) 60 | using (var test2 = seq2.AsTestingSequence()) 61 | { 62 | var result = test1.Insert(test2, count + 1).Take(count); 63 | 64 | Assert.That(seq1, Is.EqualTo(result)); 65 | } 66 | } 67 | 68 | [TestCase(3, 0)] 69 | [TestCase(3, 1)] 70 | [TestCase(3, 2)] 71 | [TestCase(3, 3)] 72 | public void Insert(int count, int index) 73 | { 74 | var seq1 = Enumerable.Range(1, count); 75 | var seq2 = new[] { 97, 98, 99 }; 76 | 77 | using (var test1 = seq1.AsTestingSequence()) 78 | using (var test2 = seq2.AsTestingSequence()) 79 | { 80 | var result = test1.Insert(test2, index); 81 | var expectations = seq1.Take(index).Concat(seq2).Concat(seq1.Skip(index)); 82 | Assert.That(result, Is.EqualTo(expectations)); 83 | } 84 | } 85 | 86 | [Test] 87 | public void InsertIsLazy() 88 | { 89 | new BreakingSequence().Insert(new BreakingSequence(), 0); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /MoreLinq.Test/PrependTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | using NUnit.Framework; 22 | using NUnit.Framework.Interfaces; 23 | 24 | [TestFixture] 25 | public class PrependTest 26 | { 27 | [Test] 28 | public void PrependWithNonEmptyTailSequence() 29 | { 30 | string[] tail = { "second", "third" }; 31 | var head = "first"; 32 | var whole = tail.Prepend(head); 33 | whole.AssertSequenceEqual("first", "second", "third"); 34 | } 35 | 36 | [Test] 37 | public void PrependWithEmptyTailSequence() 38 | { 39 | string[] tail = { }; 40 | var head = "first"; 41 | var whole = tail.Prepend(head); 42 | whole.AssertSequenceEqual("first"); 43 | } 44 | 45 | [Test] 46 | public void PrependWithNullHead() 47 | { 48 | string[] tail = { "second", "third" }; 49 | string head = null; 50 | var whole = tail.Prepend(head); 51 | whole.AssertSequenceEqual(null, "second", "third"); 52 | } 53 | 54 | [Test] 55 | public void PrependIsLazyInTailSequence() 56 | { 57 | new BreakingSequence().Prepend("head"); 58 | } 59 | 60 | [TestCaseSource(nameof(PrependManySource))] 61 | public int[] PrependMany(int[] head, int[] tail) 62 | { 63 | return tail.Aggregate(head.AsEnumerable(), MoreEnumerable.Prepend).ToArray(); 64 | } 65 | 66 | public static IEnumerable PrependManySource => 67 | from x in Enumerable.Range(0, 11) 68 | from y in Enumerable.Range(1, 11) 69 | select new 70 | { 71 | Head = Enumerable.Range(0, y).Select(n => 0 - n).ToArray(), 72 | Tail = Enumerable.Range(1, x).ToArray(), 73 | } 74 | into e 75 | select new TestCaseData(e.Head, e.Tail) 76 | .SetName("Head = [" + string.Join(", ", e.Head) + "], " + 77 | "Tail = [" + string.Join(", ", e.Tail) + "]") 78 | .Returns(e.Tail.Reverse().Concat(e.Head).ToArray()); 79 | 80 | [Test] 81 | public void PrependWithSharedSource() 82 | { 83 | var first = new [] { 1 }.Prepend(2); 84 | var second = first.Prepend(3).Prepend(4); 85 | var third = first.Prepend(4).Prepend(8); 86 | 87 | second.AssertSequenceEqual(4, 3, 2, 1); 88 | third.AssertSequenceEqual(8, 4, 2, 1); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /MoreLinq/ZipImpl.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2018 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq 19 | { 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Collections; 23 | 24 | static partial class MoreEnumerable 25 | { 26 | delegate TResult Folder(params T[] args); 27 | 28 | static IEnumerable ZipImpl( 29 | IEnumerable s1, 30 | IEnumerable s2, 31 | IEnumerable s3, 32 | IEnumerable s4, 33 | Func resultSelector, 34 | int limit, 35 | Folder errorSelector = null) 36 | { 37 | IEnumerator e1 = null; 38 | IEnumerator e2 = null; 39 | IEnumerator e3 = null; 40 | IEnumerator e4 = null; 41 | var terminations = 0; 42 | 43 | try 44 | { 45 | e1 = s1 .GetEnumerator(); 46 | e2 = s2 .GetEnumerator(); 47 | e3 = s3?.GetEnumerator(); 48 | e4 = s4?.GetEnumerator(); 49 | 50 | while (true) 51 | { 52 | var n = 0; 53 | var v1 = Read(ref e1, ++n); 54 | var v2 = Read(ref e2, ++n); 55 | var v3 = Read(ref e3, ++n); 56 | var v4 = Read(ref e4, ++n); 57 | 58 | if (terminations <= limit) 59 | yield return resultSelector(v1, v2, v3, v4); 60 | else 61 | yield break; 62 | } 63 | } 64 | finally 65 | { 66 | e1?.Dispose(); 67 | e2?.Dispose(); 68 | e3?.Dispose(); 69 | e4?.Dispose(); 70 | } 71 | 72 | T Read(ref IEnumerator e, int n) 73 | { 74 | if (e == null || terminations > limit) 75 | return default; 76 | 77 | T value; 78 | if (e.MoveNext()) 79 | { 80 | value = e.Current; 81 | } 82 | else 83 | { 84 | e.Dispose(); 85 | e = null; 86 | terminations++; 87 | value = default; 88 | } 89 | 90 | if (errorSelector != null && terminations > 0 && terminations < n) 91 | throw errorSelector(e1, e2, e3, e4); 92 | 93 | return value; 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /MoreLinq.Test/AppendTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2008 Jonathan Skeet. All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using System.Collections.Generic; 21 | using NUnit.Framework; 22 | 23 | [TestFixture] 24 | public class AppendTest 25 | { 26 | #region Append with single head and tail sequence 27 | [Test] 28 | public void AppendWithNonEmptyHeadSequence() 29 | { 30 | var head = new[] { "first", "second" }; 31 | var tail = "third"; 32 | var whole = head.Append(tail); 33 | whole.AssertSequenceEqual("first", "second", "third"); 34 | } 35 | 36 | [Test] 37 | public void AppendWithEmptyHeadSequence() 38 | { 39 | string[] head = { }; 40 | var tail = "first"; 41 | var whole = head.Append(tail); 42 | whole.AssertSequenceEqual("first"); 43 | } 44 | 45 | [Test] 46 | public void AppendWithNullTail() 47 | { 48 | var head = new[] { "first", "second" }; 49 | string tail = null; 50 | var whole = head.Append(tail); 51 | whole.AssertSequenceEqual("first", "second", null); 52 | } 53 | 54 | [Test] 55 | public void AppendIsLazyInHeadSequence() 56 | { 57 | new BreakingSequence().Append("tail"); 58 | } 59 | #endregion 60 | 61 | [TestCaseSource(nameof(ContactManySource))] 62 | public void AppendMany(int[] head, int[] tail) 63 | { 64 | tail.Aggregate(head.AsEnumerable(), (xs, x) => xs.Append(x)) 65 | .AssertSequenceEqual(head.Concat(tail)); 66 | } 67 | 68 | public static IEnumerable ContactManySource => 69 | from x in Enumerable.Range(0, 11) 70 | from y in Enumerable.Range(1, 20 - x) 71 | select new 72 | { 73 | Head = Enumerable.Range(1, x).ToArray(), 74 | Tail = Enumerable.Range(x + 1, y).ToArray(), 75 | } 76 | into e 77 | select new TestCaseData(e.Head, 78 | e.Tail).SetName("Head = [" + string.Join(", ", e.Head) + "], " + 79 | "Tail = [" + string.Join(", ", e.Tail) + "]"); 80 | 81 | [Test] 82 | public void AppendWithSharedSource() 83 | { 84 | var first = new [] { 1 }.Append(2); 85 | var second = first.Append(3).Append(4); 86 | var third = first.Append(4).Append(8); 87 | 88 | second.AssertSequenceEqual(1, 2, 3, 4); 89 | third.AssertSequenceEqual(1, 2, 4, 8); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /MoreLinq.Test/UnfoldTest.cs: -------------------------------------------------------------------------------- 1 | #region License and Terms 2 | // MoreLINQ - Extensions to LINQ to Objects 3 | // Copyright (c) 2017 Leandro F. Vieira (leandromoh). All rights reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | #endregion 17 | 18 | namespace MoreLinq.Test 19 | { 20 | using NUnit.Framework; 21 | 22 | [TestFixture] 23 | public class UnfoldTest 24 | { 25 | [Test] 26 | public void UnfoldInfiniteSequence() 27 | { 28 | var result = MoreEnumerable.Unfold(1, x => (Result: x, State: x + 1), 29 | _ => true, 30 | e => e.State, 31 | e => e.Result) 32 | .Take(100); 33 | 34 | var expectations = MoreEnumerable.Generate(1, x => x + 1).Take(100); 35 | 36 | Assert.That(result, Is.EqualTo(expectations)); 37 | } 38 | 39 | [Test] 40 | public void UnfoldFiniteSequence() 41 | { 42 | var result = MoreEnumerable.Unfold(1, x => (Result: x, State: x + 1), 43 | e => e.Result <= 100, 44 | e => e.State, 45 | e => e.Result); 46 | 47 | var expectations = MoreEnumerable.Generate(1, x => x + 1).Take(100); 48 | 49 | Assert.That(result, Is.EqualTo(expectations)); 50 | } 51 | 52 | [Test] 53 | public void UnfoldIsLazy() 54 | { 55 | MoreEnumerable.Unfold(0, BreakingFunc.Of(), 56 | BreakingFunc.Of<(int, int), bool>(), 57 | BreakingFunc.Of<(int, int), int>(), 58 | BreakingFunc.Of<(int, int), int>()); 59 | } 60 | 61 | 62 | [Test] 63 | public void UnfoldSingleElementSequence() 64 | { 65 | var result = MoreEnumerable.Unfold(0, x => (Result: x, State: x + 1), 66 | x => x.Result == 0, 67 | e => e.State, 68 | e => e.Result); 69 | 70 | var expectations = new[] { 0 }; 71 | 72 | Assert.That(result, Is.EqualTo(expectations)); 73 | } 74 | 75 | [Test] 76 | public void UnfoldEmptySequence() 77 | { 78 | var result = MoreEnumerable.Unfold(0, x => (Result: x, State: x + 1), 79 | x => x.Result < 0, 80 | e => e.State, 81 | e => e.Result); 82 | Assert.That(result, Is.Empty); 83 | } 84 | } 85 | } 86 | --------------------------------------------------------------------------------