在前兩幾天的Kata中,多多少少都看到一些LINQ的操作,例如Any, Distinct。今天會在多介紹一些LINQ較常用的操作與其能達到什麼效果。
在String average中,可以看到很多方法都在針對陣列做不同的操作,例如CalculateAverage使用for迴圈算總和,或ToNumbers把string轉換int陣列。
public class StringAverage
{
private readonly Dictionary<string, int> _numberDict = new Dictionary<string, int>()
{
{"zero", 0},
{"one", 1},
{"two", 2},
{"three", 3},
{"four", 4},
{"five", 5},
{"six", 6},
{"seven", 7},
{"eight", 8},
{"nine", 9}
};
private const int InvalidNumber = -1;
private const string InvalidStringNumber = "n/a";
public string AverageString(string stringNumbers)
{
var nums = ToNumbers(stringNumbers);
if (HasInvalidNumber(nums))
{
return InvalidStringNumber;
}
return ToString(CalculateAverage(nums));
}
private int[] ToNumbers(string str)
{
var stringNumbers = str.Split(' ');
var numbers = new int[stringNumbers.Length];
for (var i = 0; i < stringNumbers.Length; i++)
{
numbers[i] = ToNumber(stringNumbers[i]);
}
return numbers;
}
private bool HasInvalidNumber(int[] numbers)
{
foreach (var number in numbers)
{
if (number.Equals(InvalidNumber))
return true;
}
return false;
}
private int CalculateAverage(int[] numbers)
{
var sum = 0;
foreach (var number in numbers)
{
sum += number;
}
return sum / numbers.Length;
}
private int ToNumber(string stringNumber)
{
return _numberDict.ContainsKey(stringNumber) ? _numberDict[stringNumber] : InvalidNumber;
}
private string ToString(int number)
{
return _numberDict.ContainsValue(number)
? _numberDict.First(x => x.Value == number).Key
: InvalidStringNumber;
}
}
在HasInvalidNumber(int[] numbers)中,判斷numbers裡面是否存在至少一個InvalidNumber時,可以使用Count()來取代原本邏輯。
return numbers.Count(x => x == InvalidNumber) != 0
但調整成Any()則會讓語意更精準一點。
return numbers.Any(x => x == InvalidNumber);
值得一提的是,另一個常用的操作All(),可以判斷集合中是否全部元素都符合條件,也是一個很常用的操作。
CalculateAverage(int[] numbers)計算numbers的平均時,可以使用Sum()除以number數量。
return numbers.Sum() / numbers.Length;
或者使用Average()並取Floor。
return (int)Math.Floor(numbers.Average());
在ToNumbers(string str)中,把string轉成int陣列時,則可以使用Select()。
return str.Split(' ').Select(x => ToNumber(x)).ToArray()
可以發現原本要三四行才能表達的邏輯,使用LINQ就一行解決。
對於LINQ所包含都是一些對集合常用到的操作,很多語言也有類似的函式庫可以使用。要是使用的語言沒有類似的函式庫,建議可以自己實作,讓之後操作集合時節省時間。除了上面提到的LINQ操作,之後會再搭配其他場景多介紹一些其他的操作。