首先解析這份題目要得需求是甚麼

輸入兩個字串 a1 和 a2 ,輸出的字串陣列內容為 a2每一個字串陣列元素中包含a1任一個陣列元素的的字串,並且將其排序輸出,不可重複

聽起來很饒口 就看看他的範例唄

a1是要比對的字串陣列 [“arp”, “live”, “strong”]

a2是要被比對的字串陣列 [“lively”, “alive”, “harp”, “sharp”, “armstrong”]

以”arp”為例,他會比對到 “harp” 和 “sharp” 但是 我的輸出只能輸出一個 “arp” 這樣

以上的範例可以方便我來拆解這一次的需求

  • Contains方法 用來找尋包含的字串元素
  • 比對在輸出結果有沒有重複的字串 一樣是用 Contains
  • 最後的排序 OrderBy

起手就先以a1和a2各1個元素的比對來做測試案例起手,a1的元素是arp,a2的元素是aaa

程式碼如下 我預期的結果要是空的字串陣列

[TestMethod]
public void Input_arpAnd_aaa_Should_Be_EmptyArray()
/{
var actual = Kata.inArray(new string[] /{"arp"/}, new string[] /{"aaa"/});
var expected = new string[] /{ /};
Assert.AreEqual(expected,actual);
/}

而Production Code 則生成了下面這個樣子

public static string[] inArray(string[] array1, string[] array2)
/{
 return new string[]/{/};
/}

很理所當然的 這一個測試案例亮了第一次的紅燈

接下來用最簡單的方式讓紅燈變成綠燈,直接Return一個空的字串陣列XDDD

然後把剛才的筆誤Assert.AreEqual更改成 CollectionAssert.AreEqual 因為是比較陣列的關係所以要使用 CollectionAssert.AreEqual

再來新增一個會發生錯誤且Prodction Code 更改幅度為最小的測試案例,那就是會回傳正確答案的字串了

[TestMethod]
public void Input_arpAnd_aaa_Should_Be_EmptyArray()
/{
var actual = Kata.inArray(new string[] /{"arp"/}, new string[] /{"arp"/});
var expected = new string[] /{"arp" /};
CollectionAssert.AreEqual(expected,actual);
/}

很正常的,這一個測試案例會亮你紅燈,就將程式碼更改為

public static string[] inArray(string[] array1, string[] array2)
/{
List<string> result = new List<string>();
foreach (var s in array2)
/{ 
 if (s.Equals(array1[0]) )
 /{
   result.Add(s);
 /}
/}
return result.ToArray();
/}

直接宣告一個result字串陣列變數,方便我直接用add的方法就在foreach內新增一個字元,不用去標記index為多少
然後只用一個Foreach來完成這一次的需求,並且判斷有沒有包含(這裡的Equal當初寫錯,是後來才發現寫錯的),雖然把包含方法誤寫成Equal但還是通過了測試案例,亮了綠燈

接下來新增第三個測試案例,一樣是以可能最小步的方式來思考測試案例的方向,第三個測試案例就這樣產生了

[TestMethod]
public void Input_arpAnd_aaa_Should_Be_EmptyArray()
/{
var actual = Kata.inArray(new string[] /{"ss", "arp"/}, new string[] /{"arp"/});
var expected = new string[] /{"arp"/};
CollectionAssert.AreEqual(expected,actual);
/}

因為上一個測試案例所更改的 Production Code 只有找第一個 a1 元素來做比對,這一次就故意把他新增成兩個,很理所當然的,這一個測試案例也產生了紅燈的結果

所以在 Production Code 加上了第二個 Foreach 迴圈,這個迴圈以目前的測資來說 也會是沒有問題的,所以也亮了綠燈

public static string[] inArray(string[] array1, string[] array2)
/{
 List<string> result = new List<string>();
 foreach (var a2 in array2)
 /{
     foreach (var a1 in array1)
     /{
         if (a2.Equals(a1))
         /{
             result.Add(a2);
         /}
     /}
 /}
 return result.ToArray();
/}

亮了綠燈之後要檢視程式碼

這時候就發現不應該使用 Equals 而是要使用Contains 、 result add的不應該是 a2 而要是 a1、上層的迴圈應該要是array1 下層的則是array2

就把Production Code改成以下的樣子

public static string[] inArray(string[] array1, string[] array2)
/{
var result = new List<string>();
foreach (var a1 in array1)
    foreach (var a2 in array2)
        if (a2.Contains(a1))
            result.Add(a1);

 return result.ToArray();
/}

接下來再新增一個測試案例,這個測試案例是為了避免重複的結果,所以測試案例中的a2有多一個包含arp的字串

[TestMethod]
public void Input_ss_arp_And_art_starpoint_garp_Should_Be_arp()
/{
    var actual = Kata.inArray(new string[] /{ "ss", "arp" /}, new string[] /{ "art", "starpoint","garp" /});
    var expected = new string[] /{ "arp" /};
    CollectionAssert.AreEqual(expected, actual);
/}

一樣這一個測試案例使我的專案亮了紅燈

接下來就把Production Code更改成下面這個樣子 讓他再新增元素時除了判斷有無包含之外,還判斷原有的字串陣列中有沒有包含一樣的元素,如此一來就可以把這個測試案例亮成綠燈

public static string[] inArray(string[] array1, string[] array2)
/{
var result = new List<string>();
foreach (var a1 in array1)
    foreach (var a2 in array2)
        if (a2.Contains(a1) && !result.Contains(a1))
            result.Add(a1);

 return result.ToArray();
/}

再來就是最後一個需求,排序的部分,所以新增了一個需要排序才能成功的測試案例,其測試案例如下

[TestMethod]
public void Input_bc_abc_And_bbbc_dsssaabcasd_Should_Be_arp()
/{
    var actual = Kata.inArray(new string[] /{ "bc","abc" /}, new string[] /{ "bbbc","dsssaabcasd"/});
    var expected = new string[] /{ "abc","bc" /};
    CollectionAssert.AreEqual(expected, actual);
/}

這個測試案例我故意把 a 開頭的比較字串放在 a1 的第二個元素 b開頭擺在第一個,如此一來我的測試案例就會亮紅燈 

接下來只需要在我返回字串陣列的時候用Linq排序就可以完成這個需求了,也因此亮了綠燈

public static string[] inArray(string[] array1, string[] array2)
/{
    var result = new List<string>();
    foreach (var a1 in array1)
        foreach (var a2 in array2)
            if (a2.Contains(a1) && !result.Contains(a1))
                result.Add(a1);
    return result.OrderBy(x => x).ToArray();
/}

這一次的所有測試案例如下

    [TestClass]
    public class UnitTest1
    /{
        [TestMethod]
        public void Input_arpAnd_aaa_Should_Be_EmptyArray()
        /{
            var actual = Kata.inArray(new string[] /{ "arp" /}, new string[] /{ "aaa" /});
            var expected = new string[] /{ /};
            CollectionAssert.AreEqual(expected, actual);
        /}

        [TestMethod]
        public void Input_arpAndarp_Should_Be_arpOfArray()
        /{
            var actual = Kata.inArray(new string[] /{ "arp" /}, new string[] /{ "arp" /});
            var expected = new string[] /{ "arp" /};
            CollectionAssert.AreEqual(expected, actual);
        /}

        [TestMethod]
        public void Input_ss_arpAndarp_Should_Be_arpOfArray()
        /{
            var actual = Kata.inArray(new string[] /{ "ss", "arp" /}, new string[] /{ "arp" /});
            var expected = new string[] /{ "arp" /};
            CollectionAssert.AreEqual(expected, actual);
        /}

        [TestMethod]
        public void Input_ss_arp_And_art_starpoint_Should_Be_arp()
        /{
            var actual = Kata.inArray(new string[] /{ "ss", "arp" /}, new string[] /{ "art", "starpoint" /});
            var expected = new string[] /{ "arp" /};
            CollectionAssert.AreEqual(expected, actual);
        /}

        [TestMethod]
        public void Input_ss_arp_And_art_starpoint_garp_Should_Be_arp()
        /{
            var actual = Kata.inArray(new string[] /{ "ss", "arp" /}, new string[] /{ "art", "starpoint","garp" /});
            var expected = new string[] /{ "arp" /};
            CollectionAssert.AreEqual(expected, actual);
        /}

        [TestMethod]
        public void Input_bc_abc_And_bbbc_dsssaabcasd_Should_Be_arp()
        /{
            var actual = Kata.inArray(new string[] /{ "bc","abc" /}, new string[] /{ "bbbc","dsssaabcasd"/});
            var expected = new string[] /{ "abc","bc" /};
            CollectionAssert.AreEqual(expected, actual);
        /}

        [TestMethod]
        public void CodewarsExampleTest()
        /{
            var actual = Kata.inArray(new string[] /{ "arp", "live", "strong" /},
                new string[] /{ "lively", "alive", "harp", "sharp", "armstrong" /});
            var expected = new string[] /{ "arp", "live", "strong" /};
            CollectionAssert.AreEqual(expected, actual);
        /}
    /}

接下來就把程式提交,就可以看到美妙的綠燈亮出來啦

不過最重要的是在提交之後可以看見別人所寫的程式碼,其中有一個人寫的程式碼跟我的邏輯相同但他們以Linq的方式寫出來,也更精簡,如下

心得:

在這次的練習過稱中儘管不小心把Contains方法寫成Equal 也把 加入的字串a1 寫成 a2 還有 迴圈比較也寫反,但也因為後面的測試案例修改以及每一次的重新審視Production Code而及早發現程式碼發生的問題,所以覺得除了自己的測試案例還有進步的空間之外還有自己在寫Code的時候也要更加謹慎才能更有效率地把程式完成。


91在介紹codewars以及跟我私聊幾句時說了下面這段話

我們需要找到一種持續給自己回饋的方式,才能持續改善
所以 scrum 裡面有 iteration (迭代)
所以有 retrospective
一切都是持續改善的基本要素

我想Codewars就是一個很棒的回饋方式,因為你以為你已經寫到很精簡的Code時,在提交之後就會發現一個新的世界!!!