---
# System prepended metadata

title: C# 練習 - 在陣列中找出連續重複出現項目
tags: [yield]

---

# 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`