# C# 練習 - 在陣列中找出連續重複出現項目
## 需求
題目出自[黑暗大的 blog](https://blog.darkthread.net/blog/find-repeated-item-group/?fbclid=IwAR3JdZPuYXKbDB-KAV_L3VkEivXiCgJQvrE0NvrkWAbZT5H63-MImWAyLXw), 手癢也來寫看看
在陣列挑出連續重複出現的項目,例如要從陣列 [A, B, B, C, X, C, C, B, B, D, D, D] 挑出 [B, B]、[C, C]、[B, B]、[D, D, D] 四個群組。
## 解法
````C#=
namespace WA.Utilities;
public class ArrayHelper
{
/// <summary>
/// what-在陣列挑出連續重複出現的項目
/// 例如要從陣列 [A, B, B, C, X, C, C, B, B, D, D, D] 挑出 [B, B]、[C, C]、[B, B]、[D, D, D] 四個群組。
/// how-使用兩個指針, 遍歷陣列,在遇到新值時判斷是否已遇過多個連續相同的值
/// </summary>
/// <param name="dataSource">陣列長度至少是1</param>
/// <returns></returns>
public static IEnumerable<int[]> SubarrayOfRepeatValue(int[] dataSource)
{
int beginPointer=0, endPointer=0;
int current = dataSource[0];
for (int idx = 1; idx < dataSource.Length; idx++)
{
if (dataSource[idx] == current)
{
endPointer = idx;
continue;
}
// 遇到新值,將二個指針之間的array傳回
var computeResult = ComputeRepeatItems(beginPointer, endPointer, current);
if (computeResult.Length>0) yield return computeResult;
beginPointer = idx;
endPointer = idx;
current = dataSource[idx];
}
var lastResult = ComputeRepeatItems(beginPointer, endPointer, current);
if (lastResult.Length>0) yield return lastResult;
}
private static int[] ComputeRepeatItems(int beginPointer,
int endPointer, int current)
{
if (beginPointer >= endPointer) return Enumerable.Empty<int>().ToArray();
int itemValue = current;
int length = endPointer - beginPointer + 1;
return Enumerable.Repeat(itemValue, length).ToArray();
}
}
````
### 單元測試
````C#=
namespace WA.Utilities.UnitTests;
public class ArrayHelperTests
{
[TestCase("2,2,2","2,2,2")]
[TestCase("2,2,2,99", "2,2,2")]
[TestCase("99,2,2,2", "2,2,2")]
[TestCase("2,99,2,2,2", "2,2,2")]
[TestCase("2,2,2,99,2", "2,2,2")]
public void SubarrayOfRepeatValue_有1個連續重複出現的項目_傳回1個陣列(string source, string expectedValue)
{
var dataSource = ParseSource(source);
int expectedLength = 1;
int[] expected = ParseSource(expectedValue);
IEnumerable<int[]> items = ArrayHelper.SubarrayOfRepeatValue(dataSource);
Assert.AreEqual(expectedLength, items.Count());
CollectionAssert.AreEqual(expected, items.First());
}
[TestCase("2,2,3,3,3,3", "2,2;3,3,3,3")]
[TestCase("2,2,5,3,3,3,3", "2,2;3,3,3,3")]
[TestCase("33,2,2,5,3,3,3,3,99", "2,2;3,3,3,3")]
[TestCase("33,205,2,2,5,3,3,3,3,99,391", "2,2;3,3,3,3")]
[TestCase("1,2,2,3,4,3,3,2,2,5,5,5", "2,2;3,3;2,2;5,5,5")]
public void SubarrayOfRepeatValue_有多個連續重複出現的項目_傳回多個陣列的序列(string source, string expectedValue)
{
var dataSource = ParseSource(source);
IEnumerable<int[]> expectedResult = ParseExpected(expectedValue);
int expectedLength = expectedResult.Count();
IEnumerable<int[]> items = ArrayHelper.SubarrayOfRepeatValue(dataSource);
Assert.AreEqual(expectedLength, items.Count());
CollectionAssert.AreEqual(expectedResult,items);
}
private IEnumerable<int[]> ParseExpected(string expectedValue)
{
return expectedValue.Split(';').Select(item => ParseSource(item));
}
private int[] ParseSource(string source)
{
return source.Split(',').Select(int.Parse).ToArray();
}
}
````
###### tags: `yield`