Skip to content

Commit 0ec9b4f

Browse files
committed
Added Tuplewise operator
1 parent 5ad0a65 commit 0ec9b4f

File tree

9 files changed

+538
-31
lines changed

9 files changed

+538
-31
lines changed

MoreLinq.Test/MoreLinq.Test.csproj

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@
6060
<Compile Include="SampleData.cs" />
6161
<Compile Include="Scope.cs" />
6262
<Compile Include="SequenceReader.cs" />
63+
<Compile Include="TuplewiseTest.g.cs">
64+
<DesignTime>True</DesignTime>
65+
<AutoGen>True</AutoGen>
66+
<DependentUpon>TuplewiseTest.g.tt</DependentUpon>
67+
</Compile>
6368
<Compile Include="WatchableEnumerator.cs" />
6469
</ItemGroup>
6570

@@ -78,7 +83,15 @@
7883
</ItemGroup>
7984

8085
<ItemGroup>
86+
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
8187
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
8288
</ItemGroup>
8389

90+
<ItemGroup>
91+
<None Update="TuplewiseTest.g.tt">
92+
<Generator>TextTemplatingFileGenerator</Generator>
93+
<LastGenOutput>TuplewiseTest.g.cs</LastGenOutput>
94+
</None>
95+
</ItemGroup>
96+
8497
</Project>

MoreLinq.Test/TuplewiseTest.g.cs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#region License and Terms
2+
// MoreLINQ - Extensions to LINQ to Objects
3+
// Copyright (c) 2019 Phillip Palk. 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 TuplewiseTest
26+
{
27+
private void TuplewiseNWide<TSource, TResult, TFunc>(Func<IEnumerable<TSource>, TFunc, IEnumerable<TResult>> tuplewise, TFunc resultSelector, IEnumerable<TSource> source, params TResult[] fullResult)
28+
{
29+
var arity = resultSelector.GetType().GetGenericArguments().Length - 1;
30+
31+
for (var i = 0; i < fullResult.Length; ++i)
32+
using (var ts = source.Take(i).AsTestingSequence())
33+
Assert.That(tuplewise(ts, resultSelector), Is.EqualTo(fullResult.Take(i - arity + 1)));
34+
}
35+
36+
private void TuplewiseNWideInt<TFunc>(Func<IEnumerable<int>, TFunc, IEnumerable<int>> tuplewise, TFunc resultSelector)
37+
{
38+
const int rangeLen = 100;
39+
var arity = resultSelector.GetType().GetGenericArguments().Length - 1;
40+
41+
TuplewiseNWide(
42+
tuplewise,
43+
resultSelector,
44+
Enumerable.Range(1, rangeLen),
45+
Enumerable.Range(1, rangeLen - (arity - 1)).Select(x => x * arity + Enumerable.Range(1, arity - 1).Sum()).ToArray()
46+
);
47+
}
48+
49+
private void TuplewiseNWideString<TFunc>(Func<IEnumerable<char>, TFunc, IEnumerable<string>> tuplewise, TFunc resultSelector)
50+
{
51+
const string alphabet = "abcdefghijklmnopqrstuvwxyz";
52+
var arity = resultSelector.GetType().GetGenericArguments().Length - 1;
53+
54+
TuplewiseNWide(
55+
tuplewise,
56+
resultSelector,
57+
alphabet,
58+
Enumerable.Range(0, alphabet.Length - (arity - 1)).Select(i => alphabet.Skip(i).Take(arity)).ToArray()
59+
);
60+
}
61+
62+
[Test]
63+
public void TuplewiseIsLazy()
64+
{
65+
new BreakingSequence<object>().Tuplewise(BreakingFunc.Of<object, object, int>());
66+
new BreakingSequence<object>().Tuplewise(BreakingFunc.Of<object, object, object, int>());
67+
new BreakingSequence<object>().Tuplewise(BreakingFunc.Of<object, object, object, object, int>());
68+
}
69+
70+
[Test]
71+
public void TuplewiseIntegers()
72+
{
73+
TuplewiseNWideInt<Func<int, int, int>>((source, func) => MoreEnumerable.Tuplewise(source, func), (a, b ) => a + b );
74+
TuplewiseNWideInt<Func<int, int, int, int>>((source, func) => MoreEnumerable.Tuplewise(source, func), (a, b, c ) => a + b + c );
75+
TuplewiseNWideInt<Func<int, int, int, int, int>>((source, func) => MoreEnumerable.Tuplewise(source, func), (a, b, c, d) => a + b + c + d);
76+
}
77+
78+
[Test]
79+
public void TuplewiseStrings()
80+
{
81+
TuplewiseNWideString<Func<char, char, string>>((source, func) => MoreEnumerable.Tuplewise(source, func), (a, b ) => string.Join(string.Empty, a, b ));
82+
TuplewiseNWideString<Func<char, char, char, string>>((source, func) => MoreEnumerable.Tuplewise(source, func), (a, b, c ) => string.Join(string.Empty, a, b, c ));
83+
TuplewiseNWideString<Func<char, char, char, char, string>>((source, func) => MoreEnumerable.Tuplewise(source, func), (a, b, c, d) => string.Join(string.Empty, a, b, c, d));
84+
}
85+
}
86+
}

MoreLinq.Test/TuplewiseTest.g.tt

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
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) 2019 Phillip Palk. 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.Test
24+
{
25+
using System;
26+
using System.Collections.Generic;
27+
using NUnit.Framework;
28+
29+
[TestFixture]
30+
public class TuplewiseTest
31+
{
32+
private void TuplewiseNWide<TSource, TResult, TFunc>(Func<IEnumerable<TSource>, TFunc, IEnumerable<TResult>> tuplewise, TFunc resultSelector, IEnumerable<TSource> source, params TResult[] fullResult)
33+
{
34+
var arity = resultSelector.GetType().GetGenericArguments().Length - 1;
35+
36+
for (var i = 0; i < fullResult.Length; ++i)
37+
using (var ts = source.Take(i).AsTestingSequence())
38+
Assert.That(tuplewise(ts, resultSelector), Is.EqualTo(fullResult.Take(i - arity + 1)));
39+
}
40+
41+
private void TuplewiseNWideInt<TFunc>(Func<IEnumerable<int>, TFunc, IEnumerable<int>> tuplewise, TFunc resultSelector)
42+
{
43+
const int rangeLen = 100;
44+
var arity = resultSelector.GetType().GetGenericArguments().Length - 1;
45+
46+
TuplewiseNWide(
47+
tuplewise,
48+
resultSelector,
49+
Enumerable.Range(1, rangeLen),
50+
Enumerable.Range(1, rangeLen - (arity - 1)).Select(x => x * arity + Enumerable.Range(1, arity - 1).Sum()).ToArray()
51+
);
52+
}
53+
54+
private void TuplewiseNWideString<TFunc>(Func<IEnumerable<char>, TFunc, IEnumerable<string>> tuplewise, TFunc resultSelector)
55+
{
56+
const string alphabet = "abcdefghijklmnopqrstuvwxyz";
57+
var arity = resultSelector.GetType().GetGenericArguments().Length - 1;
58+
59+
TuplewiseNWide(
60+
tuplewise,
61+
resultSelector,
62+
alphabet,
63+
Enumerable.Range(0, alphabet.Length - (arity - 1)).Select(i => alphabet.Skip(i).Take(arity)).ToArray()
64+
);
65+
}
66+
67+
<# const int max = 4;
68+
const string alphabet = "abcdefghijklmnopqrstuvwxyz";
69+
#>
70+
[Test]
71+
public void TuplewiseIsLazy()
72+
{
73+
<# for (int i = 2; i <= max; ++i) {
74+
var funcTypeArgs = string.Join(" ", Enumerable.Repeat("object,", i).Concat(Enumerable.Repeat(" ", max - i)));
75+
#>
76+
new BreakingSequence<object>().Tuplewise(BreakingFunc.Of<<#= funcTypeArgs #> int>());
77+
<# } #>
78+
}
79+
80+
[Test]
81+
public void TuplewiseIntegers()
82+
{
83+
<# for (int i = 2; i <= max; ++i) {
84+
var funcTypeArgs = string.Join(" ", Enumerable.Repeat("int,", i).Concat(Enumerable.Repeat(" ", max - i)));
85+
var functorArgs = string.Join(", ", Enumerable.Range(1, i).Select(j => alphabet.Substring(j - 1, 1))) + new string(' ', 3 * (max - i));
86+
var functorBody = string.Join(" + ", Enumerable.Range(1, i).Select(j => alphabet.Substring(j - 1, 1))) + new string(' ', 4 * (max - i));
87+
#>
88+
TuplewiseNWideInt<Func<<#= funcTypeArgs #> int>>((source, func) => MoreEnumerable.Tuplewise(source, func), (<#= functorArgs #>) => <#= functorBody #>);
89+
<# } #>
90+
}
91+
92+
[Test]
93+
public void TuplewiseStrings()
94+
{
95+
<# for (int i = 2; i <= max; ++i) {
96+
var funcTypeArgs = string.Join(" ", Enumerable.Repeat("char,", i).Concat(Enumerable.Repeat(" ", max - i)));
97+
var functorArgs = string.Join(", ", Enumerable.Range(1, i).Select(j => alphabet.Substring(j - 1, 1))) + new string(' ', 3 * (max - i));
98+
#>
99+
TuplewiseNWideString<Func<<#= funcTypeArgs #> string>>((source, func) => MoreEnumerable.Tuplewise(source, func), (<#= functorArgs #>) => string.Join(string.Empty, <#= functorArgs #>));
100+
<# } #>
101+
}
102+
}
103+
}

MoreLinq/Extensions.g.cs

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3893,13 +3893,12 @@ public static partial class PairwiseExtension
38933893
/// only returned as the predecessor of the second element.
38943894
/// </summary>
38953895
/// <typeparam name="TSource">The type of the elements of <paramref name="source"/>.</typeparam>
3896-
/// <typeparam name="TResult">The type of the element of the returned sequence.</typeparam>
3896+
/// <typeparam name="TResult">The type of the elements of the returned sequence.</typeparam>
38973897
/// <param name="source">The source sequence.</param>
3898-
/// <param name="resultSelector">A transform function to apply to
3899-
/// each pair of sequence.</param>
3900-
/// <returns>
3901-
/// Returns the resulting sequence.
3902-
/// </returns>
3898+
/// <param name="resultSelector">A transform function to apply to each pair of <paramref name="source"/>.</param>
3899+
/// <returns>Returns the resulting sequence.</returns>
3900+
/// <exception cref="ArgumentNullException"><paramref name="source"/> is null</exception>
3901+
/// <exception cref="ArgumentNullException"><paramref name="resultSelector"/> is null</exception>
39033902
/// <remarks>
39043903
/// This operator uses deferred execution and streams its results.
39053904
/// </remarks>
@@ -6670,6 +6669,73 @@ public static TResult TrySingle<T, TCardinality, TResult>(this IEnumerable<T> so
66706669

66716670
}
66726671

6672+
/// <summary><c>Tuplewise</c> extension.</summary>
6673+
6674+
[GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")]
6675+
public static partial class TuplewiseExtension
6676+
{
6677+
/// <summary>
6678+
/// Returns a sequence resulting from applying a function to each
6679+
/// element in the source sequence and its
6680+
/// predecessor, with the exception of the first element which is
6681+
/// only returned as the predecessor of the second element.
6682+
/// </summary>
6683+
/// <typeparam name="TSource">The type of the elements of <paramref name="source"/>.</typeparam>
6684+
/// <typeparam name="TResult">The type of the elements of the returned sequence.</typeparam>
6685+
/// <param name="source">The source sequence.</param>
6686+
/// <param name="resultSelector">A transform function to apply to each pair of <paramref name="source"/>.</param>
6687+
/// <returns>Returns the resulting sequence.</returns>
6688+
/// <exception cref="ArgumentNullException"><paramref name="source"/> is null</exception>
6689+
/// <exception cref="ArgumentNullException"><paramref name="resultSelector"/> is null</exception>
6690+
/// <remarks>
6691+
/// This operator uses deferred execution and streams its results.
6692+
/// </remarks>
6693+
6694+
public static IEnumerable<TResult> Tuplewise<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TSource, TResult> resultSelector)
6695+
=> MoreEnumerable.Tuplewise(source, resultSelector);
6696+
6697+
/// <summary>
6698+
/// Returns a sequence resulting from applying a function to each
6699+
/// element in the source sequence and its
6700+
/// 2 predecessors, with the exception of the first and second elements which are
6701+
/// only returned as the predecessors of the third element.
6702+
/// </summary>
6703+
/// <typeparam name="TSource">The type of the elements of <paramref name="source"/>.</typeparam>
6704+
/// <typeparam name="TResult">The type of the elements of the returned sequence.</typeparam>
6705+
/// <param name="source">The source sequence.</param>
6706+
/// <param name="resultSelector">A transform function to apply to each triplet of <paramref name="source"/>.</param>
6707+
/// <returns>Returns the resulting sequence.</returns>
6708+
/// <exception cref="ArgumentNullException"><paramref name="source"/> is null</exception>
6709+
/// <exception cref="ArgumentNullException"><paramref name="resultSelector"/> is null</exception>
6710+
/// <remarks>
6711+
/// This operator uses deferred execution and streams its results.
6712+
/// </remarks>
6713+
6714+
public static IEnumerable<TResult> Tuplewise<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource, TResult> resultSelector)
6715+
=> MoreEnumerable.Tuplewise(source, resultSelector);
6716+
6717+
/// <summary>
6718+
/// Returns a sequence resulting from applying a function to each
6719+
/// element in the source sequence and its
6720+
/// 3 predecessors, with the exception of the first 3 elements which are
6721+
/// only returned as the predecessors of the 4th element.
6722+
/// </summary>
6723+
/// <typeparam name="TSource">The type of the elements of <paramref name="source"/>.</typeparam>
6724+
/// <typeparam name="TResult">The type of the elements of the returned sequence.</typeparam>
6725+
/// <param name="source">The source sequence.</param>
6726+
/// <param name="resultSelector">A transform function to apply to each 4-tuple of <paramref name="source"/>.</param>
6727+
/// <returns>Returns the resulting sequence.</returns>
6728+
/// <exception cref="ArgumentNullException"><paramref name="source"/> is null</exception>
6729+
/// <exception cref="ArgumentNullException"><paramref name="resultSelector"/> is null</exception>
6730+
/// <remarks>
6731+
/// This operator uses deferred execution and streams its results.
6732+
/// </remarks>
6733+
6734+
public static IEnumerable<TResult> Tuplewise<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource, TSource, TResult> resultSelector)
6735+
=> MoreEnumerable.Tuplewise(source, resultSelector);
6736+
6737+
}
6738+
66736739
/// <summary><c>Window</c> extension.</summary>
66746740

66756741
[GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")]

MoreLinq/MoreLinq.csproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
- Transpose
103103
- TraverseBreadthFirst
104104
- TraverseDepthFirst
105+
- Triplewise
105106
- TrySingle
106107
- Unfold
107108
- Window
@@ -172,6 +173,10 @@
172173
<Generator>TextTemplatingFileGenerator</Generator>
173174
<LastGenOutput>ToDelimitedString.g.cs</LastGenOutput>
174175
</None>
176+
<None Update="Tuplewise.g.tt">
177+
<Generator>TextTemplatingFileGenerator</Generator>
178+
<LastGenOutput>Tuplewise.g.cs</LastGenOutput>
179+
</None>
175180
</ItemGroup>
176181

177182
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
@@ -236,6 +241,11 @@
236241
<AutoGen>True</AutoGen>
237242
<DependentUpon>ToDelimitedString.g.tt</DependentUpon>
238243
</Compile>
244+
<Compile Update="Tuplewise.g.cs">
245+
<DesignTime>True</DesignTime>
246+
<AutoGen>True</AutoGen>
247+
<DependentUpon>Tuplewise.g.tt</DependentUpon>
248+
</Compile>
239249
</ItemGroup>
240250

241251
<ItemGroup>

MoreLinq/Pairwise.cs

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,12 @@ static partial class MoreEnumerable
2929
/// only returned as the predecessor of the second element.
3030
/// </summary>
3131
/// <typeparam name="TSource">The type of the elements of <paramref name="source"/>.</typeparam>
32-
/// <typeparam name="TResult">The type of the element of the returned sequence.</typeparam>
32+
/// <typeparam name="TResult">The type of the elements of the returned sequence.</typeparam>
3333
/// <param name="source">The source sequence.</param>
34-
/// <param name="resultSelector">A transform function to apply to
35-
/// each pair of sequence.</param>
36-
/// <returns>
37-
/// Returns the resulting sequence.
38-
/// </returns>
34+
/// <param name="resultSelector">A transform function to apply to each pair of <paramref name="source"/>.</param>
35+
/// <returns>Returns the resulting sequence.</returns>
36+
/// <exception cref="ArgumentNullException"><paramref name="source"/> is null</exception>
37+
/// <exception cref="ArgumentNullException"><paramref name="resultSelector"/> is null</exception>
3938
/// <remarks>
4039
/// This operator uses deferred execution and streams its results.
4140
/// </remarks>
@@ -49,24 +48,6 @@ static partial class MoreEnumerable
4948
/// </example>
5049

5150
public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TSource, TResult> resultSelector)
52-
{
53-
if (source == null) throw new ArgumentNullException(nameof(source));
54-
if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
55-
56-
return _(); IEnumerable<TResult> _()
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-
}
51+
=> source.Tuplewise(resultSelector);
7152
}
7253
}

0 commit comments

Comments
 (0)