Một C # cho mỗi vòng lặp lặp qua một Danh sách <T> theo thứ tự nào?


82

Tôi đã tự hỏi về thứ tự mà một vòng lặp foreach trong C # lặp qua một System.Collections.Generic.List<T>đối tượng.

Tôi đã tìm thấy một câu hỏi khác về cùng chủ đề, nhưng tôi không cảm thấy rằng nó trả lời câu hỏi của tôi làm tôi hài lòng.

Ai đó nói rằng không có thứ tự nào được xác định. Nhưng như một người khác nói, thứ tự nó đi qua một mảng là cố định (từ 0 đến Độ dài-1). 8.8.4 Tuyên bố foreach

Người ta cũng nói rằng bất kỳ lớp tiêu chuẩn nào có thứ tự cũng được giữ nguyên như vậy (ví dụ List<T>). Tôi không thể tìm thấy bất kỳ tài liệu nào để sao lưu điều đó. Vì vậy, đối với tất cả những gì tôi biết bây giờ nó có thể hoạt động như vậy, nhưng có thể trong phiên bản .NET tiếp theo, nó sẽ khác (mặc dù nó có thể khó xảy ra).

Tôi cũng đã xem List(t).Enumeratortài liệu mà không gặp may.

Một câu hỏi liên quan khác nói rằng đối với Java, nó được đề cập cụ thể trong tài liệu:

List.iterator()trả về một trình lặp trên các phần tử trong danh sách này theo trình tự thích hợp. "

Tôi đang tìm kiếm một cái gì đó tương tự trong tài liệu C #.

Cảm ơn trước.

Chỉnh sửa: Cảm ơn tất cả các bạn cho tất cả các câu trả lời của bạn (tuyệt vời làm sao tôi nhận được rất nhiều câu trả lời). Điều tôi hiểu từ tất cả các câu trả lời là List<T>nó luôn lặp lại theo thứ tự lập chỉ mục của nó. Nhưng tôi vẫn muốn thấy một tài liệu hòa bình rõ ràng nói rõ điều này, tương tự như tài liệu Java trênList .

Câu trả lời:


13

Trên trang Nguồn tham chiếu của Microsoft dành cho Người List<T>điều tra, nó được tuyên bố rõ ràng rằng việc lặp lại được thực hiện từ 0 đến Độ dài-1:

internal Enumerator(List<T> list) {
    this.list = list;
    index = 0;
    version = list._version;
    current = default(T);
}

public bool MoveNext() {

    List<T> localList = list;

    if (version == localList._version && ((uint)index < (uint)localList._size)) 
    {                                                     
        current = localList._items[index];                    
        index++;
        return true;
    }
    return MoveNextRare();
}

Hy vọng nó vẫn phù hợp với ai đó


102

Về cơ bản nó tùy thuộc vào sự IEnumeratorthực hiện - nhưng đối với một List<T>nó sẽ luôn luôn đi theo thứ tự tự nhiên của danh sách, tức là thứ tự như indexer: list[0], list[1], list[2], vv

Tôi không tin rằng nó được lập thành tài liệu rõ ràng - ít nhất, tôi chưa tìm thấy tài liệu như vậy - nhưng tôi nghĩ bạn có thể coi nó là được đảm bảo. Bất kỳ thay đổi nào đối với thứ tự đó sẽ phá vỡ mọi loại mã một cách vô nghĩa. Trên thực tế, tôi sẽ ngạc nhiên khi thấy bất kỳ triển khai IList<T>nào không tuân theo điều này. Phải thừa nhận rằng sẽ rất vui khi thấy nó được ghi lại cụ thể ...


Tôi thực sự vừa kiểm tra một câu trả lời cách đây 5 giây và sắp đăng một cái gì đó tương tự. Bạn quá nhanh!
Michael G

Cảm ơn cho câu trả lời của bạn. Có một số tài liệu đảm bảo điều này?
Matthijs Wessels

1
@Michael G: Mặc dù vậy, tôi sẽ không dựa vào mã ví dụ MSDN làm tài liệu. Tôi đã thấy quá nhiều lỗi kinh hoàng trong đó.
Jon Skeet

1
ai có thể vui lòng cung cấp câu trả lời tương tự về mảng không?
yazanpro

12
@yazanpro: foreachchắc chắn sẽ lặp lại theo thứ tự với một mảng.
Jon Skeet

8

Trong liên kết của bạn, câu trả lời được chấp nhận nêu trong Đặc tả ngôn ngữ C # Phiên bản 3.0, trang 240 :

Thứ tự mà foreach duyệt qua các phần tử của một mảng, như sau: Đối với mảng một chiều, các phần tử được duyệt theo thứ tự chỉ mục tăng dần, bắt đầu bằng chỉ số 0 và kết thúc bằng chỉ số Độ dài - 1. Đối với mảng nhiều chiều, các phần tử được duyệt qua sao cho các chỉ số của thứ nguyên ngoài cùng bên phải được tăng lên đầu tiên, sau đó là thứ nguyên bên trái tiếp theo, và cứ tiếp tục như vậy ở bên trái. Ví dụ sau in ra từng giá trị trong một mảng hai chiều, theo thứ tự phần tử:

using System;
class Test
{
  static void Main() {
      double[,] values = {
          {1.2, 2.3, 3.4, 4.5},
          {5.6, 6.7, 7.8, 8.9}
      };
      foreach (double elementValue in values)
          Console.Write("{0} ", elementValue);
      Console.WriteLine();
  }
}

Sản lượng được tạo ra như sau: 1,2 2,3 3,4 4,5 5,6 6,7 7,8 8,9 Trong ví dụ

int[] numbers = { 1, 3, 5, 7, 9 };
foreach (var n in numbers) Console.WriteLine(n);
the type of n is inferred to be int, the element type of numbers.

2
Có, nhưng đây là cho một mảng. Nó cũng tự động giữ cho lớp Danh sách <T>?
Matthijs Wessels

2
List <T> sử dụng một mảng cho kho dự trữ của nó. Vì vậy, có.
Joel Mueller

9
Nhưng đó là một chi tiết thực hiện. Danh sách <T> không bắt buộc phải sử dụng một mảng làm kho dự trữ của nó.
Eric Lippert

3
Tôi muốn chỉ ra tài liệu cho List <T> (trong mã ví dụ): "Lớp List <(Of <(T>)>) là lớp tương đương chung của lớp ArrayList. Nó triển khai IList <(Of <(T>)>) giao diện chung sử dụng một mảng có kích thước được tăng động theo yêu cầu. " (nhấn mạnh của tôi)
RCIX

Hmm, tôi đoán nó luôn sử dụng một mảng sau đó. Tuy nhiên, điều đó có nghĩa là nó không thể trả về một điều tra viên đã đảo ngược?
Matthijs Wessels

4

Thứ tự được xác định bởi trình lặp được sử dụng để duyệt qua một tập hợp dữ liệu bằng cách sử dụng vòng lặp foreach.

Nếu bạn đang sử dụng một tập hợp chuẩn có thể lập chỉ mục (chẳng hạn như Danh sách), thì nó sẽ duyệt qua tập hợp bắt đầu bằng chỉ mục 0 và di chuyển lên trên.

Nếu bạn cần kiểm soát thứ tự, bạn có thể kiểm soát cách xử lý lặp lại bộ sưu tập bằng cách triển khai IEnumerable của riêng bạn hoặc bạn có thể sắp xếp danh sách theo cách bạn muốn trước khi thực hiện vòng lặp foreach.

Điều này giải thích cách Enumerator hoạt động cho Danh sách chung. Lúc đầu, phần tử hiện tại chưa được xác định và sử dụng MoveNext để đến mục tiếp theo.

Nếu bạn đọc MoveNext, nó chỉ ra rằng nó sẽ bắt đầu với phần tử đầu tiên của tập hợp và từ đó chuyển sang phần tử tiếp theo cho đến khi nó đến cuối tập hợp.


Cảm ơn vì đã trả lời và bổ sung (Mọi người trả lời quá nhanh, tôi gần như không thể theo kịp). Tôi cũng đã đọc nó. Có lẽ tôi chỉ là một <từ để chỉ định ai đó muốn quá chính xác>, nhưng tôi cảm thấy rằng khi họ nói "phần tử đầu tiên", họ có nghĩa là phần tử đầu tiên sẽ được lặp lại, không phải phần tử đầu tiên theo theo thứ tự của lớp đã lặp.
Matthijs Wessels

Chà nếu điều quan trọng là bạn chắc chắn rằng nó sẽ diễn ra theo cách bạn mong đợi, thì cách tốt nhất là làm theo những gì tôi đã nói và tự thực hiện IEnumerable.
Brendan Enrick

1

Danh sách dường như trả lại các mặt hàng theo thứ tự mà chúng có trong cửa hàng hỗ trợ - vì vậy nếu chúng được thêm vào danh sách theo cách đó, chúng sẽ được trả lại theo cách đó.

Nếu chương trình của bạn phụ thuộc vào thứ tự, bạn có thể muốn sắp xếp nó trước khi duyệt qua danh sách.

Nó hơi ngớ ngẩn đối với các tìm kiếm tuyến tính - nhưng nếu bạn cần thứ tự theo một cách nhất định, đặt cược tốt nhất của bạn là tạo các mặt hàng theo thứ tự đó.


1

Tôi vừa phải làm một điều gì đó tương tự như hack mã nhanh chóng, mặc dù nó không hoạt động với những gì tôi đang cố gắng thực hiện nó đã sắp xếp lại danh sách cho tôi.

Sử dụng LINQ để thay đổi thứ tự

         DataGridViewColumn[] gridColumns = new DataGridViewColumn[dataGridView1.Columns.Count];
         dataGridView1.Columns.CopyTo(gridColumns, 0); //This created a list of columns

         gridColumns = (from n in gridColumns
                        orderby n.DisplayIndex descending
                        select n).ToArray(); //This then changed the order based on the displayindex

Tôi không hiểu điều này liên quan đến câu hỏi như thế nào. Mã của bạn thậm chí không sử dụng a List. Tôi nghĩ rằng bạn đã hiểu sai ý tôi với "danh sách".
Matthijs Wessels 19/09/12

Ngoài ra, tại sao bạn sao chép nội dung của Columnsđể gridColumnsđầu tiên? Tôi nghĩ rằng bạn cũng có thể chỉ cần làm:DataGridViewColumn[] gridColumns = dataGridView1.Columns.OrderByDescending(n => n.DisplayIndex).ToArray();
Matthijs Wessels

@MatthijsWessels Sẽ không khó để thay đổi điều đó để sử dụng Danh sách, nếu bạn muốn.
Austin Henley

@AustinHenley Bạn có thể thực hiện một bước trước trên IOrderedEnumerable, nhưng đó không phải là những gì câu hỏi là về. Bạn cũng có thể làm với ToList thay vì ToArray, nhưng sau đó bạn chỉ có lại một Danh sách và câu hỏi liệu một foreach sau đó có lặp lại các mục theo thứ tự được chỉ định hay không vẫn chưa được trả lời.
Matthijs Wessels 25/09/12
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.