diff --git a/MoreLinq.Test/StepTest.cs b/MoreLinq.Test/StepTest.cs new file mode 100644 index 000000000..0f1fca4c3 --- /dev/null +++ b/MoreLinq.Test/StepTest.cs @@ -0,0 +1,82 @@ +#region License and Terms +// MoreLINQ - Extensions to LINQ to Objects +// Copyright (c) 2021 Atif Aziz. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace MoreLinq.Test +{ + using System.Collections.Generic; + using NUnit.Framework; + + [TestFixture] + public class StepTest + { + static readonly IEnumerable TestData = new [] + { + new TestCaseData(new int[0], new[] { 1, 1 }) + { + ExpectedResult = new(bool, int)[0] + }, + new TestCaseData(new int[0], new[] { 0, 0 }) + { + ExpectedResult = new(bool, int)[0] + }, + new TestCaseData(new[] { 42 }, new[] { 0, 0, 1 }) + { + ExpectedResult = new[] { (42, 1), (42, 0), (42, 0) } + }, + new TestCaseData(new[] { 1, 2, 3, 4, 5 }, new[] { 1, 1, 1, 1, 1 }) + { + ExpectedResult = new[] { (1, 1), (2, 1), (3, 1), (4, 1), (5, 1) } + }, + new TestCaseData(new[] { 1, 2, 3, 4, 5 }, new[] { 2, 2, 2, 2, 2 }) + { + ExpectedResult = new[] { (1, 1), (3, 2), (5, 2) } + }, + new TestCaseData(new[] { 1, 2, 3, 4, 5 }, new[] { 10 }) + { + ExpectedResult = new[] { (1, 1) } + }, + new TestCaseData(new[] { 1, 2, 3, 4, 5 }, new[] { 1, 1 }) + { + ExpectedResult = new[] { (1, 1), (2, 1), (3, 1) } + }, + new TestCaseData(new[] { 1, 2, 3 }, new[] { 1, 1, 1, 1, 1 }) + { + ExpectedResult = new[] { (1, 1), (2, 1), (3, 1) } + }, + new TestCaseData(new[] { 42 }, new[] { 0, 0, 0 }) + { + ExpectedResult = new[] { (42, 1), (42, 0), (42, 0), (42, 0) } + }, + new TestCaseData(new[] { 1, 2, 3 }, new[] { 1, 0, 1, 0, 1, 0 }) + { + ExpectedResult = new[] { (1, 1), (2, 1), (2, 0), (3, 1), (3, 0) } + }, + new TestCaseData(new[] { 1, 2, 3 }, new[] { 1, -1, 1, -1, 1, -1 }) + { + ExpectedResult = new[] { (1, 1), (2, 1), (2, 0), (3, 1), (3, 0) } + } + }; + + [TestCaseSource(nameof(TestData))] + public object Step(int[] xs, int[] steps) + { + using var source = xs.AsTestingSequence(); + using var ts = steps.AsTestingSequence(); + return source.Step(ts).ToArray(); + } + } +} diff --git a/MoreLinq/Extensions.g.cs b/MoreLinq/Extensions.g.cs index b40abc470..7b802a409 100644 --- a/MoreLinq/Extensions.g.cs +++ b/MoreLinq/Extensions.g.cs @@ -5567,6 +5567,32 @@ public static bool StartsWith(this IEnumerable first, IEnumerable secon } + /// Step extension. + + [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] + public static partial class StepExtension + { + /// + /// Steps through a sequence based on another sequence of zero or + /// positive steps to take between elements. + /// + /// The type of elements in . + /// The source sequence. + /// + /// Sequence of zero or positive steps to take where a negative step is + /// treated the same as zero. + /// + /// A sequence of items from paired with + /// steps from . + /// + /// This operator uses deferred execution and streams its results. + + public static IEnumerable<(T Item, int Step)> + Step(this IEnumerable source, IEnumerable steps) + => MoreEnumerable. Step(source, steps); + + } + /// Subsets extension. [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] diff --git a/MoreLinq/Step.cs b/MoreLinq/Step.cs new file mode 100644 index 000000000..452ae8149 --- /dev/null +++ b/MoreLinq/Step.cs @@ -0,0 +1,74 @@ +#region License and Terms +// MoreLINQ - Extensions to LINQ to Objects +// Copyright (c) 2021 Atif Aziz. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace MoreLinq +{ + using System; + using System.Collections.Generic; + + partial class MoreEnumerable + { + /// + /// Steps through a sequence based on another sequence of zero or + /// positive steps to take between elements. + /// + /// The type of elements in . + /// The source sequence. + /// + /// Sequence of zero or positive steps to take where a negative step is + /// treated the same as zero. + /// + /// A sequence of items from paired with + /// steps from . + /// + /// This operator uses deferred execution and streams its results. + + public static IEnumerable<(T Item, int Step)> + Step(this IEnumerable source, IEnumerable steps) + { + if (source is null) throw new ArgumentNullException(nameof(source)); + if (steps is null) throw new ArgumentNullException(nameof(steps)); + + return _(); IEnumerable<(T, int)> _() + { + using var item = source.GetEnumerator(); + + if (!item.MoveNext()) + yield break; + yield return (item.Current, 1); + + foreach (var step in steps) + { + if (step > 0) + { + for (var i = 0; i < step; i++) + { + if (!item.MoveNext()) + yield break; + } + + yield return (item.Current, step); + } + else + { + yield return (item.Current, 0); + } + } + } + } + } +}