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