From f36d7e5b18397a76c440f30a1e18b91567d69e30 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Fri, 8 Jan 2021 17:01:17 +0100 Subject: [PATCH 1/3] Add Step extension --- MoreLinq/Extensions.g.cs | 25 +++++++++++++++ MoreLinq/Step.cs | 69 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 MoreLinq/Step.cs diff --git a/MoreLinq/Extensions.g.cs b/MoreLinq/Extensions.g.cs index b40abc470..884715894 100644 --- a/MoreLinq/Extensions.g.cs +++ b/MoreLinq/Extensions.g.cs @@ -5567,6 +5567,31 @@ public static bool StartsWith(this IEnumerable first, IEnumerable secon } + /// Step extension. + + [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] + public static partial class StepExtension + { + /// + /// Iterates through a sequence based on another sequence of Boolean + /// values indicating when to step to the next element. + /// + /// The type of elements in . + /// The source sequence. + /// Sequence of Boolean values. + /// + /// A sequence of elements from where + /// each element is duplicated while the Boolean from + /// is false. + /// + /// This operator uses deferred execution and streams its results. + + public static IEnumerable<(bool Moved, T Item)> + 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..3805d9720 --- /dev/null +++ b/MoreLinq/Step.cs @@ -0,0 +1,69 @@ +#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 + { + /// + /// Iterates through a sequence based on another sequence of Boolean + /// values indicating when to step to the next element. + /// + /// The type of elements in . + /// The source sequence. + /// Sequence of Boolean values. + /// + /// A sequence of elements from where + /// each element is duplicated while the Boolean from + /// is false. + /// + /// This operator uses deferred execution and streams its results. + + public static IEnumerable<(bool Moved, T Item)> + 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<(bool, T)> _() + { + using var item = source.GetEnumerator(); + + if (!item.MoveNext()) + yield break; + yield return (true, item.Current); + + foreach (var step in steps) + { + if (step) + { + if (!item.MoveNext()) + break; + yield return (true, item.Current); + } + else + { + yield return (false, item.Current); + } + } + } + } + } +} From e6717f27a70af0a9aeb8c21f86ec8244ff33c09b Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Sat, 9 Jan 2021 18:18:53 +0100 Subject: [PATCH 2/3] Replace Boolean with integral steps --- MoreLinq/Extensions.g.cs | 17 +++++++++-------- MoreLinq/Step.cs | 35 ++++++++++++++++++++--------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/MoreLinq/Extensions.g.cs b/MoreLinq/Extensions.g.cs index 884715894..7b802a409 100644 --- a/MoreLinq/Extensions.g.cs +++ b/MoreLinq/Extensions.g.cs @@ -5573,21 +5573,22 @@ public static bool StartsWith(this IEnumerable first, IEnumerable secon public static partial class StepExtension { /// - /// Iterates through a sequence based on another sequence of Boolean - /// values indicating when to step to the next element. + /// 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 Boolean values. + /// + /// Sequence of zero or positive steps to take where a negative step is + /// treated the same as zero. /// - /// A sequence of elements from where - /// each element is duplicated while the Boolean from - /// is false. + /// A sequence of items from paired with + /// steps from . /// /// This operator uses deferred execution and streams its results. - public static IEnumerable<(bool Moved, T Item)> - Step(this IEnumerable source, IEnumerable steps) + public static IEnumerable<(T Item, int Step)> + Step(this IEnumerable source, IEnumerable steps) => MoreEnumerable. Step(source, steps); } diff --git a/MoreLinq/Step.cs b/MoreLinq/Step.cs index 3805d9720..452ae8149 100644 --- a/MoreLinq/Step.cs +++ b/MoreLinq/Step.cs @@ -23,44 +23,49 @@ namespace MoreLinq partial class MoreEnumerable { /// - /// Iterates through a sequence based on another sequence of Boolean - /// values indicating when to step to the next element. + /// 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 Boolean values. + /// + /// Sequence of zero or positive steps to take where a negative step is + /// treated the same as zero. /// - /// A sequence of elements from where - /// each element is duplicated while the Boolean from - /// is false. + /// A sequence of items from paired with + /// steps from . /// /// This operator uses deferred execution and streams its results. - public static IEnumerable<(bool Moved, T Item)> - Step(this IEnumerable source, IEnumerable steps) + 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<(bool, T)> _() + return _(); IEnumerable<(T, int)> _() { using var item = source.GetEnumerator(); if (!item.MoveNext()) yield break; - yield return (true, item.Current); + yield return (item.Current, 1); foreach (var step in steps) { - if (step) + if (step > 0) { - if (!item.MoveNext()) - break; - yield return (true, item.Current); + for (var i = 0; i < step; i++) + { + if (!item.MoveNext()) + yield break; + } + + yield return (item.Current, step); } else { - yield return (false, item.Current); + yield return (item.Current, 0); } } } From 4e9f023e2789e6347c890b0defb55d3c9693ab4e Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Sat, 9 Jan 2021 18:21:34 +0100 Subject: [PATCH 3/3] Add tests --- MoreLinq.Test/StepTest.cs | 82 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 MoreLinq.Test/StepTest.cs 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(); + } + } +}