Có thể bắt đầu lặp từ một phần tử khác với phần tử đầu tiên bằng cách sử dụng foreach không?


86

Tôi đang nghĩ đến việc triển khai IEnumerable cho bộ sưu tập tùy chỉnh của mình (một cây) để tôi có thể sử dụng foreach để đi qua cây của mình. Tuy nhiên theo như tôi biết thì foreach luôn bắt đầu từ phần tử đầu tiên của bộ sưu tập. Tôi muốn chọn foreach phần tử nào bắt đầu. Có thể bằng cách nào đó thay đổi phần tử mà từ đó foreach bắt đầu không?


1
Tôi sẽ làm theo các nguyên tắc bất ngờ nhỏ nhất: en.wikipedia.org/wiki/Principle_of_least_astonishment
ChaosPandion

Nếu bạn không bắt đầu từ phần tử đầu tiên, làm thế nào để bạn xác định hành vi của trình vòng lặp? Điều gì xảy ra khi nó đến cuối dãy? Sau đó nó có quay trở lại phần tử đầu tiên và lặp lại các phần tử còn lại không?
Dan J

Bình luận của @ ChaosPandion là nơi tôi sẽ đi đến những câu hỏi đó. :)
Dan J

Câu trả lời:


162

Đúng. Làm như sau:

Collection<string> myCollection = new Collection<string>;

foreach (string curString in myCollection.Skip(3))
    //Dostuff

Skiplà một hàm IEnumerable bỏ qua tuy nhiên nhiều bạn chỉ định bắt đầu từ chỉ mục hiện tại. Mặt khác, nếu bạn muốn sử dụng chỉ ba đầu tiên bạn sẽ sử dụng .Take:

foreach (string curString in myCollection.Take(3))

Chúng thậm chí có thể được ghép nối với nhau, vì vậy nếu bạn chỉ muốn có 4-6 mục, bạn có thể làm:

foreach (string curString in myCollection.Skip(3).Take(3))

Tốt cuộc gọi. WTB tự động hoàn tất (gahh không thể nhớ tên thật của nó) trong stackoverflow;)
MoarCodePlz

Điều này thực sự bỏ qua hay nó chỉ tạo một bản sao? IE sẽ hai thể khác nhau: foreach(List<string> row in rows.skip(1)){ row[0] = "newInfo"; } vs for(int i=1; i<rows.Count;i++){ List<string> row = rows[i]; row[0] = "newStuff"; }
TigerBear

25

Cách dễ nhất là sử dụng Skipphương thức trong LINQ to Objects cho việc này, để bỏ qua một số phần tử nhất định:

foreach (var value in sequence.Skip(1)) // Skips just one value
{
    ...
}

Rõ ràng chỉ cần thay đổi 1 cho bất kỳ giá trị nào khác để bỏ qua một số phần tử khác ...

Tương tự, bạn có thể sử dụng Takeđể giới hạn số lượng phần tử được trả về.

Bạn có thể đọc thêm về cả hai (và có liên quan SkipWhileTakeWhilephương pháp) trong loạt Edulinq tôi viết blog .


Jon, điều này không có nguy cơ xảy ra ngoại lệ nếu "chuỗi" là Null?
WEFX

@WEFX: Chúng tôi không biết liệu sequencecó thể hợp pháp nullhay không. Có lẽ OP có thể xử lý mà bản thân - nó không thực sự là một phần của câu hỏi ...
Jon Skeet

5

Bạn có thể dùng Enumerable.Skip để bỏ qua một số phần tử và bắt đầu nó ở đó.

Ví dụ:

foreach(item in theTree.Skip(9))  // Skips the first 9 items
{
    // Do something

Tuy nhiên, nếu bạn đang viết một cái cây, bạn có thể muốn cung cấp một thành viên trên chính mục cây đó sẽ trả về một cái mới IEnumerable<T>sẽ liệt kê từ đó xuống. Điều này, có khả năng, hữu ích hơn về lâu dài.


Một cái gì đó như thế IEnumerable<T> SubTree(rootIndex)nào? Tốt cuộc gọi!
Dan J

Cảm ơn bạn đã trả lời, bỏ qua có vẻ đầy hứa hẹn, đọc thông tin MSDN về bỏ qua, tôi kết luận rằng có thể có thể viết phương thức StartFrom (cây IEnumerable <MyTree> này, phần tử MyTreeElement) sẽ là một phương thức mở rộng cho IEnumerable <MyTree> mà sẽ trả về IEnumerable <MyTreeElement> mà từ đó tôi sẽ bắt đầu lặp lại. Sau đó, có lẽ tôi có thể sử dụng phương thức này như foreach (phần tử var trong tree.StartFrom (someElement))).
Inferno

@inferno: Có, bạn có thể dễ dàng làm điều đó. Tuy nhiên, tôi sẽ chỉ thêm một phương thức / thuộc tính vào MyTreeElement giống như sau:, IEnumerable<MyTreeElement> Childrenvì vậy bạn có thể thực hiện: foreach(var item in someElement.Children)- rõ ràng hơn nhiều so với việc sử dụng các phương thức mở rộng IMO.
Reed Copsey

-1

Foreachsẽ lặp lại bộ sưu tập của bạn theo cách được xác định bởi việc triển khai của bạn IEnumerable. Vì vậy, mặc dù bạn có thể bỏ qua các phần tử (như đã đề xuất ở trên), về mặt kỹ thuật, bạn vẫn đang lặp lại các phần tử theo cùng một thứ tự.

Không chắc bạn đang cố gắng đạt được gì, nhưng lớp của bạn có thể có nhiều IEnumerablethuộc tính, mỗi thuộc tính liệt kê các phần tử theo một thứ tự cụ thể.


-1

Nếu bạn muốn bỏ qua việc đọc Hàng trong a DataGridView, hãy thử cách này

foreach (DataGridViewRow row in dataGridView1.Rows.Cast<DataGridViewRow().Skip(3))

Nếu bạn muốn sao chép nội dung của một DataGridViewhàng sang các hàng bỏ qua khác, hãy thử cách này,

foreach (DataGridViewRow row in dataGridView1.Rows.Cast<DataGridViewRow>().Skip(3))
{
    foreach (DataGridViewCell cell in row.Cells)
    {
        string value = cell.Value.ToString();
        dataGridView2.Rows[i].Cells[j].Value = cell.Value.ToString();
        j++;
    }
    i++;
    j = 0;
}

điều này sao chép nội dung từ một DataGridViewsang một khác bỏ qua 3 hàng.


Điều này không trả lời câu hỏi đã được đặt ra - câu hỏi hoàn toàn không đề cập đến DataGridView(hoặc thậm chí là khung giao diện người dùng).
NightOwl888

@ NightOwl888 điều này đã được trả lời vì câu hỏi là về việc bỏ qua một số lần lặp và lặp lại sau đó trong vòng lặp foreach. Trong ví dụ của tôi, tôi vừa sử dụng Skip () để áp dụng trên DataGridView.
Juned Khan Momin 21/09/18
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.