iT邦幫忙

2025 iThome 鐵人賽

DAY 4
0

在前幾天,我們學會了變數與條件判斷 (if/elseswitch)。
今天要來介紹程式裡另一個重要的工具:迴圈 (Loop)

迴圈的用途是「重複做某件事」,特別適合用在處理一整份股票清單時。


為什麼需要迴圈?

假設我們有一個股票價格清單:

double[] prices = { 80, 120, 95, 150 };

如果要檢查每一檔股票是否大於 100,你會怎麼做?

用 if/else,一支一支股票寫下來:

if (prices[0] > 100) Console.WriteLine("股票 1 進入觀察名單");
if (prices[1] > 100) Console.WriteLine("股票 2 進入觀察名單");
if (prices[2] > 100) Console.WriteLine("股票 3 進入觀察名單");
if (prices[3] > 100) Console.WriteLine("股票 4 進入觀察名單");

👉 這樣太笨重了,萬一股票有上百檔,程式就會長到天荒地老。
這時候就需要 迴圈


for 迴圈

for 適合在「知道要跑幾次」的時候使用。

double[] prices = { 80, 120, 95, 150 };

for (int i = 0; i < prices.Length; i++)
{
    if (prices[i] > 100)
    {
        Console.WriteLine($"股票 {i + 1} 價格 {prices[i]} → 進入觀察名單");
    }
}

執行結果:

股票 2 價格 120 → 進入觀察名單
股票 4 價格 150 → 進入觀察名單

foreach 迴圈

如果你只是想「逐一讀取清單裡的每個值」,foreach 會更簡潔。

double[] prices = { 80, 120, 95, 150 };

int index = 1;
foreach (var price in prices)
{
    if (price > 100)
    {
        Console.WriteLine($"股票 {index} 價格 {price} → 進入觀察名單");
    }
    index++;
}

👉 適合處理「集合 (List/Array)」的情境。


⚠️ 在迴圈中刪除資料的陷阱

很多時候,我們需要「逐一檢查清單內容,若條件成立就移除」。
直覺寫法如下 —— 但這會出錯:

var prices = new List<double> { 80, 120, 95, 150 };

foreach (var p in prices)
{
    if (p <= 100)
        prices.Remove(p); // ❌ System.InvalidOperationException
}

為什麼會爆?

因為 foreach 透過 列舉器 (Enumerator) 來讀取清單。
當你在迴圈裡修改集合(RemoveAdd),版本不一致,列舉器就會丟 InvalidOperationException,避免資料錯亂。


解決方法

解法 A:倒序 for

var prices = new List<double> { 80, 120, 95, 150 };

for (int i = prices.Count - 1; i >= 0; i--)
{
    if (prices[i] <= 100)
        prices.RemoveAt(i);
}

解法 B:先收集再刪除

var prices = new List<double> { 80, 120, 95, 150 };
var toRemove = new List<double>();

foreach (var p in prices)
{
    if (p <= 100) toRemove.Add(p);
}

foreach (var p in toRemove)
    prices.Remove(p);

解法 C:對快照操作

foreach (var p in prices.ToList())
{
    if (p <= 100) prices.Remove(p);
}

解法 D:一行解法

prices.RemoveAll(p => p <= 100);

💡 延伸補充:物件與集合

為什麼 foreach 在刪除時會丟錯?這要從「物件 (Object)」來理解。

  • List<T> 是一個 類別 (Class),當你寫:

    var prices = new List<double> { 80, 120, 95, 150 };
    

    這個 prices 就是一個 List<double> 類別的 物件 (Object)

  • 物件有狀態prices 裡的數字就是狀態。

  • 物件有行為Add()Remove()Count 都是它的功能。

foreach 用的是 列舉器 (Enumerator) 物件,會監控集合的版本。
當你在列舉中修改集合,它會檢測到版本不一致,丟出例外,保護資料一致性。

👉 這就是「物件」的特性之一:不只是資料袋,而是有規則的實體。


while 迴圈

while 適合「不知道要跑幾次,但有條件決定是否繼續」的情境。

double[] prices = { 80, 120, 95, 150 };
int i = 0;

while (i < prices.Length)
{
    if (prices[i] > 100)
    {
        Console.WriteLine($"股票 {i + 1} 價格 {prices[i]} → 進入觀察名單");
    }
    i++;
}

⚠️ 無窮迴圈的陷阱

要小心 while,如果忘記更新條件,會變成無窮迴圈:

int i = 0;
while (i < 5)
{
    Console.WriteLine("這行會跑不完...");
    // 忘記寫 i++,永遠卡住!
}

Console 完整範例

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        var prices = new List<double> { 80, 120, 95, 150 };

        Console.WriteLine("=== for 迴圈 ===");
        for (int i = 0; i < prices.Count; i++)
        {
            if (prices[i] > 100)
                Console.WriteLine($"股票 {i + 1} 價格 {prices[i]} → 進入觀察名單");
        }

        Console.WriteLine("=== foreach 迴圈 ===");
        int index = 1;
        foreach (var price in prices)
        {
            if (price > 100)
                Console.WriteLine($"股票 {index} 價格 {price} → 進入觀察名單");
            index++;
        }

        Console.WriteLine("=== while 迴圈 ===");
        int j = 0;
        while (j < prices.Count)
        {
            if (prices[j] > 100)
                Console.WriteLine($"股票 {j + 1} 價格 {prices[j]} → 進入觀察名單");
            j++;
        }

        Console.WriteLine("=== 移除小於等於 100 的股票 ===");
        prices.RemoveAll(p => p <= 100); // 精簡做法
        foreach (var price in prices)
        {
            Console.WriteLine($"剩餘股票價格:{price}");
        }
    }
}

執行結果:

=== for 迴圈 ===
股票 2 價格 120 → 進入觀察名單
股票 4 價格 150 → 進入觀察名單

=== foreach 迴圈 ===
股票 2 價格 120 → 進入觀察名單
股票 4 價格 150 → 進入觀察名單

=== while 迴圈 ===
股票 2 價格 120 → 進入觀察名單
股票 4 價格 150 → 進入觀察名單

=== 移除小於等於 100 的股票 ===
剩餘股票價格:120
剩餘股票價格:150

小結

今天我們學會了:

  • for:知道次數時最適合
  • foreach:用來逐一讀取集合
  • while:條件控制,注意無窮迴圈
  • foreach 限制:不能在迴圈中修改集合
  • 物件觀念List<T> 是物件,有狀態與行為,foreach 的列舉器會檢查集合版本

---https://ih1.redbubble.net/image.851818249.6238/st,small,507x507-pad,600x600,f8f8f8.u8.jpg

預告

明天,我們要介紹 方法 (Method) —— 怎麼把「計算股票邏輯」抽出來,避免同一段程式碼重複出現。


上一篇
Day 3 - 流程控制:if/else 與 switch
下一篇
Day 5 - 方法 (Method) 與程式邏輯封裝
系列文
30天快速上手製作WPF選股工具 — 從C#基礎到LiteDB與Web API整合11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言