Vòng lặp foreach trong lập trình C# cơ bản

Dẫn nhập

Ở các bài học trước, tất cả chúng ta đã cùng với nhau khám phá về MẢNG NHIỀᑗ CHIỀᑗ TRONG ₵#. Bây giờ tất cả chúng ta sẽ cùng khám phá về kết cấu lặp foreach trong ₵#.

Bài viết

Để đọc hiểu bài này tốt nhất các chúng ta nên có học thức cơ bản về các phần:

Trong bài học này, tất cả chúng ta sẽ cùng khám phá các vấn đề:

  • Cú pháp & phép tắc hoạt động của

    foreach

    trong ₵#

  • Sử dụng

    foreach

    trong ₵#

  • So sánh for &

    foreach

    trong ₵#

Cú pháp & phép tắc hoạt động của foreach trong ₵#

Kết cấu lặp foreach cho phép tất cả chúng ta duyệt 1 mảng hoặc 1 tập hợp (sẽ được trình bày trong bài TỔNG QUAN VỀ COLLECTION TRONG ₵#).

Một số đặc thù của foreach:

  • Foreach không duyệt mảng hoặc tập hợp thông qua chỉ số phần tử như kết cấu lặp for.
  • Foreach duyệt tuần tự các phần tử trong mảng hoặc tập hợp.
  • Foreach chỉ dùng để duyệt mảng hoặc tập hợp bên cạnh đó chẳng thể làm gì khác.

Cú pháp

foreach (<kiểu dữ liệuvàgt; <tên biếռ tạmvàgt; in <tên mảng hoặc tập hợpvàgt;)

{

              // Code giải quyết        

 }

Trong số đó:

  • Các từ khoá foreach, in là từ khoá bắt buộc.
  • <kiểu dữ liệuvàgt;

    là kiểu dữ liệu của các phần tử trong mảng hoặc tập hợp.

  • <tên biến tạmvàgt;

    là tên 1 biến tạm đại diện cho phần tử đang xét khi duyệt mảng hoặc tập hợp.

  • <tên mảng hoặc tập hợpvàgt;

    là tên của mảng hoặc tập hợp cần duyệt.

Phép tắc hoạt động

Foreach cũng có phép tắc hoạt động cũng giống như các kết cấu lặp khác rõ ràng như sau:

  • Ở vòng lặp trước nhất sẽ gán giá trị của phần tử trước nhất trong mảng vào

    biến tạm

    .

  • Thực hiện khối lệnh bên trong vòng lặp

    foreach

    .

  • Qua mỗi vòng lặp kế tiếp sẽ thực hiện kiểm soát xem đã duyệt hết mảng hoặc tập hợp chưa. Nếu chưa thì tiếp gán giá trị của phần tử hiện giờ vào

    biến tạm

    & tiếp tục thực hiện khối lệnh bên trong.

  • Nếu đã duyệt qua hết các phần tử thì vòng lặp sẽ chấm dứt.

Qua phép tắc hoạt động trên ta có thể thấy:

  • Biến tạm

    trong vòng lặp

    foreach

    sẽ tương tự với phần tử ι trong cách duyệt của vòng lặp

    for

    (đã trình bày trong bài CẤᑗ TRÚ₵ VÒNG LẶΡ FOR TRONG ₵#).

  • Qua mỗi bước lặp ta chỉ có thể thao tác với giá trị của phần tử đang xét mà chẳng thể tương tác với các phần tử đứng trước nó hay xếp sau nó (trong CẤᑗ TRÚ₵ VÒNG LẶΡ FOR TRONG ₵# thì hoàn toàn được).
  • Bằng cách duyệt của

    foreach

    ta chẳng thể biến đổi giá trị của các phần tử vì giờ đây giá trị của nó đã được copy ra một 1 biến tạm & ta chỉ có thể thao tác với

    biến tạm

    .

  • Thậm chí việc biến đổi

    giá trị

    của

    biến tạm

    cũng không được phép. Nếu ta cố làm điều đó thì sẽ gặp lỗi sau:

Sử dụng foreach trong ₵#

Trong ₵#, có những danh mục, tập hợp mà ta chẳng thể truy xuất đến các phần tử của nó thông qua chỉ số phần tử được (chẳng hạn như kiểu Danh mục – sẽ được trình bày trong bài LIST TRONG ₵# hoặc các collection, generic – sẽ được trình bày trong bài COLLECTION TRONG ₵# & bài GENERIC TRONG ₵#).

Trong trường hợp như thế, để duyệt các danh mục, tập hợp có đặc thù như trên thì foreach là lựa chọn tốt nhất.

Tất cả chúng ta sẽ khám phá sức mạnh của foreach qua các bài học sau. Còn trong bài học này mình chỉ chẳng hạn dễ dàng để các bạn có thể nắm cú pháp cũng như cách dùng foreach.

  •  Xét chương trình sau:
/*
             * Khai báo mảng một chiều IntArray & khởi tạo giá trị.
             * Các bạn có thể xem lại cú pháp này ở bài Mảng một chiều trong ₵#
             * Khai báo 1 biến Sum để chứa giá trị tổng các phần tử trong mảng IntArray.
             */
            int[] IntArray = { 1, 5, 2, 4, 6 };
            int Sum = 0;

            /*
             * Sử dụng foreach để duyệt mảng & in giá trị của các phần tử trong mảng.
             * Cùng lúc tận dụng vòng lặp để tính tổng các phần tử trong mảng.
             */
            foreach (int item in IntArray)
            {
                Console.Write("t" + item);
                Sum += item;
            }

            Console.WriteLine("n Sum = " + Sum);

Có vẻ tất cả chúng ta đã không mấy xa lạ với đoạn chương trình trên. Đoạn chương trình trên sẽ duyệt mảng để in ra các giá trị của mảng & tính tổng các phần tử trong mảng.

Nhưng thay vì sử dụng for thì mình sử dụng foreach để các bạn có thể thấy được sự tương đồng giữa các thành phần trong kết cấu foreach & CẤᑗ TRÚ₵ VÒNG LẶΡ FOR TRONG ₵#.

Kết quả khi chạy đoạn chương trình trên:

Chẳng hạn thứ 2: ta thử sử dụng foreach để duyệt mảng jagged

/*
             * Khai báo 1 mảng jagged tên là JaggedArray & khởi tạo giá trị.
             * Các bạn có thể xem lại cú pháp khai báo này ở bài Mảng nhiều chiều trong ₵#.
             */
            int[][] JaggedArray = 
                            { 
                                new int[] { 1, 2, 3 },
                                new int[] { 5, 2, 4, 1, 6},
                                new int[] { 7, 3, 4, 2, 1, 5, 9, 8}
                            };

            /*
             * Cũng giống như dùng for, ta cũng dùng 2 vòng foreach lồng vào nhau để duyệt mảng.
             */
            foreach (int[] Element in JaggedArray)
            {
                foreach (int item in Element)
                {
                    Console.Write(item + "  ");
                }
                Console.WriteLine();
            }

Ta có thể thấy cách duyệt foreach ngắn gọn hơn nhiều đối với cách duyệt bằng vòng lặp for thông thường.

Ta cũng chả quan tâm tới việc phải giải quyết độ dài mảng hay chỉ số phần tử để truy xuất 1 phần tử nào đó.

  • Kết quả khi chạy đoạn chương trình trên:

So sánh for & foreach trong ₵#

Foreach đưa trong mình một số ưu thế như:

  • Câu lệnh ngắn gọn, sẽ sử dụng.
  • Rất có lợi khi duyệt danh mục, tập hợp mà chẳng thể truy xuất thông qua chỉ số phần tử.
  • Duyệt các danh mục, tập hợp có số phần tử không xác nhận hoặc số phần tử biến đổi liên tục.

Dù rằng có nhiều ưu thế nhưng không hẳn là foreach hơn hẵn for. Cùng điểm qua một vài tiêu chuẩn để xem 2 địch thủ này ai hơn ai nhé.

Tiêu chuẩn

For

Foreach

Khả năng truy xuất phần tử

Truy xuất bỗng nhiên (có thể gọi bất kỳ phần tử nào trong mảng để sử dụng)

Truy xuất tuần tự (chỉ sử dụng được giá trị phần tử đang xét)

Biến đổi được giá trị của các phần tử

Không

Duyệt mảng, tập hợp khi không hiểu rằng số phần tử của mảng, tập hợp

Không

Năng suất (vận tốc giải quyết) (*)

So với mảng, danh mục hoặc tập hợp có khả năng truy xuất bỗng nhiên thì for sẽ chiếm ưu điểm

So với mảng, danh mục hoặc tập hợp không có khả năng truy xuất bỗng nhiên thì foreach chiếm ưu điểm

(*) Nhìn chung năng suất của for & foreach còn lệ thuộc vào kết cấu dữ liệu đang xét do đó việc so sánh này chỉ có tính chất đọc qua.

Sau đây là 2 đoạn chương trình kiểm soát vận tốc của for & foreach so với 2 kết cấu dữ liệu là mảng một chiều (có khả năng truy xuất bỗng nhiên) & danh mục link LinkedList (không có khả năng truy xuất bỗng nhiên):

Trước hết là mảng một chiều:

/* Kiểm soát vận tốc của for */

/*
             * Sử dụng 1 cái đồng hồ để đo thời gian chạy của 2 vòng lặp for & foreach
             * Ở giai đoạn này mình chỉ kiểm soát vận tốc chứ không chăm chú giải thích cú pháp
             * Các bạn có thể đọc thêm.
             */
            Stopwatch start = new Stopwatch();
            start.Start();

            int[] IntArray = new int[Int32.MaxValue / 100];
            int s = 0;
            int Length = IntArray.Length;
            for (int ι = 0; ι < Length; ι++)
            {
                s += IntArray[i];
            }

            start.Stop();
            Console.WriteLine(" Thoi gian chay cua for: {0} giay {1} mili giay", start.Elapsed.Seconds, start.Elapsed.Milliseconds);

            /* Kiểm soát vận tốc của foreach */
            Stopwatch start2 = new Stopwatch();
            start2.Start();

            int[] IntArray2 = new int[Int32.MaxValue / 100];
            int s2 = 0;

            foreach (int item in IntArray2)
            {
                s2 += item;
            }

            start2.Stop();
            Console.WriteLine(" Thoi gian chay cua foreach: {0} giay {1} mili giay", start2.Elapsed.Seconds, start2.Elapsed.Milliseconds);

  •  Đoạn chương trình mình thực hiện:
    • Khai báo 1 mảng một chiều có 20 triệu phần tử (khai báo số phần tử lớn để có thể thấy được sự chêch lệch về vận tốc)
    • Lần lượt dùng

      for

      ,

      foreach

      để duyệt mảng đó & thực hiện 1 câu lệnh nào đó.

    • Cuối cùng là xuất ra thời gian thực thi của từng trường hợp dưới dạng giây & mili giây.
  •  Kết quả khi chạy đoạn chương trình trên:
  •  Dựa theo kết quả ta có thể thấy được sự chêch lệch nhỏ về vận tốc, nếu kiểm soát với số phần tử to hơn hoặc kết cấu dữ liệu cầu kỳ hơn thì chêch lệch này càng lớn.

Kế tiếp là đến danh mục link LinkedList:

/*
             * Khai báo 1 LinkedList chưa các số nguyên int & khởi tạo giá trị cho nó.
             */
            LinkedListvàlt;intvàgt; danh mục = new LinkedListvàlt;intvàgt;();

            for (int ι = 0; ι < 100000; ι++)
            {
                danh mục.AddLast(ι);
            }

	/* Kiểm soát vận tốc của for */
            Stopwatch st = new Stopwatch();
            int s1 = 0, length = danh mục.Count;
            st.Start();
            for (int ι = 0; ι < length; ι++)
            {
                /*
                 * Vì LinkedList chẳng thể truy xuất thông qua chỉ số phần tử
                 * nên mình phải sử dụng 1 công thức bổ trợ làm điều này.
                 * & đây chính là sự giới hạn của for so với các kết cấu dữ liệu cũng giống như danh mục link này.
                 */
                s1 += danh mục.ElementAt(ι);
            }
            st.Stop();

	/* Kiểm soát vận tốc của foreach */
            Stopwatch st2 = new Stopwatch();
            int s2 = 0;
            st2.Start();
            foreach (int item in danh mục)
            {
                /*
                 * Vì foreach không quan tâm đến chỉ số phần tử nên code viết rất ngắn gọn
                 */
                s2 += item;
            }
            st2.Stop();

            /* In ra giá trị tính tổng giá trị các phần tử khi duyệt bằng for & foreach để chắc cú rằng cả 2 đều chạy đúng */
            Console.WriteLine(" s1 = {0}   s2 = {1}", s1, s2);
            Console.WriteLine(" Thoi gian chay cua for = {0} giay {1} mili giay", st.Elapsed.Seconds, st.Elapsed.Milliseconds);
            Console.WriteLine(" Thoi gian chay cua foreach = {0} giay {1} mini giay", st2.Elapsed.Seconds, st2.Elapsed.Milliseconds);

  •  Chương trình mình thực hiện:
    • Tạo 1

      LinkedList

      & thêm vào 100000 phần tử.

    • Sau đó lần lượt dùng

      for

      ,

      foreach

      duyệt

      LinkedList

      trên & tính tổng giá trị các phần tử trong mảng.

    • Cuối cùng in ra thời gian chạy của

      for

      ,

      foreach

      .

  •  Kết quả khi chạy chương trình trên là:
  •  Dựa theo kết quả chạy ta thấy sự chênh lệch là quá lớn, rõ ràng và cụ thể so với kết cấu dữ liệu cầu kỳ, không bổ trợ truy xuất thông qua chỉ số phần tử nữa thì foreach chiếm ưu điểm.

Tuỳ vào từng trường hợp mà ta nên dùng for hay foreach. Không nên lạm dụng 1 thứ quá nhiều.

Tổng kết

Bài viết bài này giúp các bạn nắm được:

  • Cú pháp của

    foreach

    trong ₵#.

  • Sử dụng

    foreach

    trong ₵#.

  • So sánh

    for

    &

    foreach

    trong ₵#.

Bài sau tất cả chúng ta sẽ khám phá về LỚΡ STRING TRONG ₵#.

Cảm ơn các bạn đã theo dõi nội dung. Hãy để lại comment hoặc phản hồi của mình để tiến triển nội dung tốt hơn. Đừng quên “Luyện tập – Thử thách – Không ngại khó”.

Luận bàn

Nếu bạn có bất kỳ khốn khó hay khúc mắc gì về khóa học, đừng ngần ngại đặt thắc mắc trong phần bên dưới hoặc trong mục HỎI & ĐÁP trên thư viện Howkteam.com để thu được sự bổ trợ từ cộng đồng.

Xem Thêm  Python While Loop - hàm trong vòng lặp while python

Viết một bình luận