Skip to content

Commit bf15061

Browse files
Oraceatifaziz
authored andcommitted
Fix Segment to not move past sequence end
This is a squashed merge of PR #691 that closes #687.
1 parent 84e2625 commit bf15061

File tree

2 files changed

+43
-21
lines changed

2 files changed

+43
-21
lines changed

MoreLinq.Test/SegmentTest.cs

+26
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
namespace MoreLinq.Test
1919
{
20+
using System.Collections.Generic;
21+
using NUnit.Framework.Interfaces;
2022
using NUnit.Framework;
2123

2224
/// <summary>
@@ -146,5 +148,29 @@ public void VerifyCanSegmentByPrevious()
146148
Assert.AreEqual(sequence.Distinct().Count(), result.Count());
147149
Assert.IsTrue(result.All(s => s.Count() == repCount));
148150
}
151+
152+
static IEnumerable<T> Seq<T>(params T[] values) => values;
153+
154+
public static readonly IEnumerable<ITestCaseData> TestData =
155+
from e in new[]
156+
{
157+
// input sequence is empty
158+
new { Source = Seq<int>(), Expected = Seq<IEnumerable<int>>() },
159+
// input sequence contains only new segment start
160+
new { Source = Seq(0, 3, 6), Expected = Seq(Seq(0), Seq(3), Seq(6)) },
161+
// input sequence do not contains new segment start
162+
new { Source = Seq(1, 2, 4, 5), Expected = Seq(Seq(1, 2, 4, 5)) },
163+
// input sequence start with a segment start
164+
new { Source = Seq(0, 1, 2, 3, 4, 5), Expected = Seq(Seq(0, 1, 2), Seq(3, 4, 5)) },
165+
// input sequence do not start with a segment start
166+
new { Source = Seq(1, 2, 3, 4, 5), Expected = Seq(Seq(1, 2), Seq(3, 4, 5)) }
167+
}
168+
select new TestCaseData(e.Source).Returns(e.Expected);
169+
170+
[Test, TestCaseSource(nameof(TestData))]
171+
public IEnumerable<IEnumerable<int>> TestSegment(IEnumerable<int> source)
172+
{
173+
return source.AsTestingSequence().Segment(v => v % 3 == 0);
174+
}
149175
}
150176
}

MoreLinq/Segment.cs

+17-21
Original file line numberDiff line numberDiff line change
@@ -76,44 +76,40 @@ public static IEnumerable<IEnumerable<T>> Segment<T>(this IEnumerable<T> source,
7676

7777
return _(); IEnumerable<IEnumerable<T>> _()
7878
{
79-
var index = -1;
8079
using var iter = source.GetEnumerator();
8180

82-
var segment = new List<T>();
83-
var prevItem = default(T);
81+
// early break
82+
if (!iter.MoveNext())
83+
yield break;
8484

8585
// ensure that the first item is always part
8686
// of the first segment. This is an intentional
8787
// behavior. Segmentation always begins with
8888
// the second element in the sequence.
89-
if (iter.MoveNext())
90-
{
91-
++index;
92-
segment.Add(iter.Current);
93-
prevItem = iter.Current;
94-
}
89+
var prevItem = iter.Current;
90+
var segment = new List<T> { iter.Current };
9591

96-
while (iter.MoveNext())
92+
for (var index = 1; iter.MoveNext(); index++)
9793
{
98-
++index;
9994
// check if the item represents the start of a new segment
100-
var isNewSegment = newSegmentPredicate(iter.Current, prevItem, index);
101-
prevItem = iter.Current;
95+
if (newSegmentPredicate(iter.Current, prevItem, index))
96+
{
97+
// yield the completed segment
98+
yield return segment;
10299

103-
if (!isNewSegment)
100+
// start a new segment
101+
segment = new List<T> { iter.Current };
102+
}
103+
else
104104
{
105105
// if not a new segment, append and continue
106106
segment.Add(iter.Current);
107-
continue;
108107
}
109-
yield return segment; // yield the completed segment
110108

111-
// start a new segment...
112-
segment = new List<T> { iter.Current };
109+
prevItem = iter.Current;
113110
}
114-
// handle the case of the sequence ending before new segment is detected
115-
if (segment.Count > 0)
116-
yield return segment;
111+
112+
yield return segment;
117113
}
118114
}
119115
}

0 commit comments

Comments
 (0)