iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 26
0
自我挑戰組

TDD - 紅燈,綠燈,重構,30天 TDD之路有你有我系列 第 26

Day26. 找出分歧者不是啦,我是說要找因數 Codewars_Find The Divisors

https://ithelp.ithome.com.tw/upload/images/20180112/20107209ZguBceT25m.png

抱..抱歉貼錯

這才是今天的題目!

https://ithelp.ithome.com.tw/upload/images/20180112/201072092711niHoUE.png

今天的題目需要找出輸入變數的因數,並且從小排序到大。
這個題目有特別註明不要找出自己跟1。
現在就來拆一下題目吧。

  1. 找出因數(除以某數餘數為0)的方法。
  2. 排序的方法。

一開始我們先來寫輸入0的測試吧!!

[TestMethod]
public void Input_0_Should_Be_Null()
{
    Assert.IsNull(Kata.Divisors(0));
}

而Production Code 也就是老樣子會長成這個樣子

public static int[] Divisors(int num)
{
    throw new System.NotImplementedException();
}

老樣子,跑個測試,沒過很正常,紅燈,commit一下

接下來把Production Code改成這個樣子

public static int[] Divisors(int num)
{
    return null;
}

接下來跑個測試,PASS! Commit~

因為1、2的輸入都預期為null所以現在就來加上輸入4的測試。
當然,你也可以自己加上1跟2的測試。

[TestMethod]
public void Input_4_Should_Be_2()
{
    CollectionAssert.AreEqual(new int[] { 2 }, Kata.Divisors(4));
}

因為這樣的話只需要考慮到輸出只有1個,所以Production Code長這樣

for (int i = 2; i <= num / 2; i++)
{
    if (num % i == 0)
    {
        return new int[] { i };
    }
}

再來是輸入6的測試,這個測試就會有多個元素的陣列了。

[TestMethod]
public void Input_6_Should_Be_2and3()
{
    CollectionAssert.AreEqual(new int[] { 2, 3 }, Kata.Divisors(6));
}

因為要記錄因數的關係,所以需要用一個List來存取他,所以Production Code就會變成這個樣子

public static int[] Divisors(int num)
{
var result = new List<int>();
for (int i = 2; i <= num / 2; i++)
{
    if (num % i == 0)
    {
        return new int[] { i };
        result.Add(i);
    }
}
return result.Count > 0 ? result.ToArray() : null;
}

這時候只要refactor一下,測試,Pass! Commit!

public static int[] Divisors(int num)
{
var result = Enumerable.Range(2, num / 2).Where(x => num % x == 0).ToArray();
return result.Length > 0 ? result : null;
}

現在已經完成所有需求啦!
所以現在就可以直接提交了。

但是Fail了,原因是因為運算時間的關係(他說我的Code寫太爛 嗚嗚)
所以我們回到剛才還沒有Refactor的地方,把演算法的問題考慮進去。
Production Code就變成這個樣子

public static int[] Divisors(int num)
{
    var result = new List<int>();
    for (int i = 2; i * i <= num; i++)
    {
        if (num % i == 0)
        {
            result.Add(i);
            result.Add(num / i);
        }
    }
    return result.Count > 0 ? result.OrderBy(x => x).Distinct().ToArray() : null;
}

以下是今天所有的測試案例

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void Input_0_Should_Be_Null()
    {
        Assert.IsNull(Kata.Divisors(0));
    }

    [TestMethod]
    public void Input_4_Should_Be_2()
    {
        CollectionAssert.AreEqual(new int[] { 2 }, Kata.Divisors(4));
    }

    [TestMethod]
    public void Input_6_Should_Be_2and3()
    {
        CollectionAssert.AreEqual(new int[] { 2, 3 }, Kata.Divisors(6));
    }

    [TestMethod]
    public void Input_15_Should_Be_3and5()
    {
        CollectionAssert.AreEqual(new int[] { 3, 5 }, Kata.Divisors(15));
    }

    [TestMethod]
    public void Input_16_Should_Be2and4and8()
    {
        CollectionAssert.AreEqual(new int[] { 2, 4, 8 }, Kata.Divisors(16));
    }

    [TestMethod]
    public void Input_253_Should_Be_11and23()
    {
        CollectionAssert.AreEqual(new int[] { 11, 23 }, Kata.Divisors(253));
    }

    [TestMethod]
    public void Input_99999999_SHould__()
    {
        CollectionAssert.AreEqual(new int[] { 3, 9, 11, 33, 73, 99, 101, 137, 219, 303, 411, 657, 803, 909, 1111, 1233, 1507, 2409, 3333, 4521, 7227, 7373, 9999, 10001, 13563, 13837, 22119, 30003, 41511, 66357, 81103, 90009, 110011, 124533, 152207, 243309, 330033, 456621, 729927, 990099, 1010101, 1369863, 3030303, 9090909, 11111111, 33333333 }, Kata.Divisors(99999999));
    }

}

最後Submit到Codewars,Pass!

https://ithelp.ithome.com.tw/upload/images/20180112/201072090SG1w7Yfr5.png

在Codewars上成功提交了~
來看一下其他人怎麼寫吧!

https://ithelp.ithome.com.tw/upload/images/20180112/20107209xFUk8Q9pV1.png

依然還是有人可以用一行Linq語法串來串去然後輸出的,超級厲害…
希望有朝一日我也能變成那個樣子XD

Git url :
https://github.com/SQZ777/Codewars_FindTheDivisors

Codewars Link:
https://www.codewars.com/kata/find-the-divisors/train/csharp

下一題,明天見!


上一篇
Day25. 史上最簡單6kyu(?) Codewars_Bit Counting
下一篇
Day27. 搶劫!你的手機號碼!? Codewars_Create Phone Number
系列文
TDD - 紅燈,綠燈,重構,30天 TDD之路有你有我30

尚未有邦友留言

立即登入留言