當想要儲存多個物件時,我們會使用Array或List。
List<string> someStrings = new List<string>();
當我們需要List有一些功能時,則會再修改List內容前加上一些邏輯。
在 Remove duplicate words 中,在把輸入字串拆分成一個一個的單字之後,直覺會想用另外一個陣列來儲存沒有重複的單字,並透過檢查重複的if判斷來去除重複
public string RemoveDuplicatedWord(string text)
{
var words = text.Split(' ');
var distinctWords = new List<string>();
foreach (var word in words)
{
if (!distinctWords.Contains(word))
{
distinctWords.Add(word);
}
}
return string.Join(" ", distinctWords);
}
此時我們若使用HashSet取代List,讓HashSet的特性幫我們去除重複的物件,就能讓代碼更為精簡。
public string RemoveDuplicatedWord(string text)
{
var words = text.Split(' ');
var distinctWords = new HashSet<string>(words);
foreach (var word in words)
{
distinctWords.Add(word);
}
return string.Join(" ", distinctWords);
}
甚至連for迴圈都可以省去
public string RemoveDuplicatedWord(string text)
{
var words = text.Split(' ');
var distinctWords = new HashSet<string>(words);
return string.Join(" ", distinctWords);
}
在Reverse polish notation calculator的例子裡,使用List用來暫時儲存計算結果的operands,在計算完成後會需要移除使用過的運算元。
public double Evaluate(string expressions)
{
var operatorDict = new Dictionary<string, Func<double, double, double>>()
{
{"+", (operator1, operator2) => operator1 + operator2 },
{"-", (operator1, operator2) => operator1 - operator2 },
{"*", (operator1, operator2) => operator1 * operator2 },
{"/", (operator1, operator2) => operator1 / operator2 },
};
var operands = new List<double>();
foreach (var expression in expressions.Split(' '))
{
if (operatorDict.ContainsKey(expression))
{
var tmp = operatorDict[expression](operands[operands.Count - 2], operands[operands.Count - 1]);
operands.RemoveAt(operands.Count - 2);
operands.RemoveAt(operands.Count - 1);
operands.Add(tmp);
}
else
{
operands.Add(Double.Parse(expression));
}
}
return operands.First();
}
如果將List改用Stack,則能用Stack First In Last Out的特性,用Pop()達到取出並移除最後一個運算元
public double Evaluate(string expressions)
{
var operatorDict = new Dictionary<string, Func<double, double, double>>()
{
{"+", (operator2, operator1) => operator1 + operator2 },
{"-", (operator2, operator1) => operator1 - operator2 },
{"*", (operator2, operator1) => operator1 * operator2 },
{"/", (operator2, operator1) => operator1 / operator2 },
};
var operands = new Stack<double>();
foreach (var expression in expressions.Split(' '))
{
if (operatorDict.ContainsKey(expression))
{
operands.Push(operatorDict[expression](operands.Pop(), operands.Pop()));
}
else
{
operands.Push(Double.Parse(expression));
}
}
return operands.First();
}
往後使用List時,不妨多想想需要的List是否還有其他特性,使用適合的資料結構能使代碼簡潔好維護。與Stack相似的資料結構,還有First In First Out的Queue,不妨可以思考一下什麼時候適合使用Queue。