Чи можна почати ітерацію з іншого елемента, ніж перший, використовуючи foreach?


86

Я думаю про впровадження IEnumerable для моєї власної колекції (дерева), щоб я міг використовувати foreach для обходу мого дерева. Однак, наскільки мені відомо, foreach завжди починається з першого елемента колекції. Я хотів би вибрати, з якого елементу починається кожен. Чи можна якось змінити елемент, з якого починається foreach?


1
Я дотримувався б принципу найменшого подиву: en.wikipedia.org/wiki/Principle_of_least_astonishment
ChaosPandion

Якщо ви не починаєте з першого елемента, як ви визначаєте поведінку ітератора? Що відбувається, коли він досягає кінця послідовності? Потім він повертається до першого елемента та перебирає інші елементи?
Dan J

Коментар @ ChaosPandion - це те, куди я йшов із цими питаннями. :)
Dan J

Відповіді:


162

Так. Виконайте наступне:

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

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

Skip- це функція IEnumerable, яка пропускає скільки б ви не вказали, починаючи з поточного індексу. З іншого боку, якби ви хотіли використовувати лише перші три, ви б використовували .Take:

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

Їх навіть можна поєднати, тому, якщо ви хочете лише 4-6 пунктів, ви можете зробити:

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

Гарний дзвінок. Автозаповнення WTB (gahh не пам’ятає справжнього його імені) у
stackoverflow

Це насправді пропускає чи просто створює копію? IE, foreach(List<string> row in rows.skip(1)){ row[0] = "newInfo"; }for(int i=1; i<rows.Count;i++){ List<string> row = rows[i]; row[0] = "newStuff"; }
якби

25

Для цього найпростіше використовувати Skipметод у LINQ to Objects, щоб пропустити задану кількість елементів:

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

Очевидно, просто змініть 1 на будь-яке інше значення, щоб пропустити різну кількість елементів ...

Так само можна використовувати Take для обмеження кількості елементів, які повертаються.

Ви можете прочитати більше про обидва ці (і пов'язані з ними методи SkipWhileта TakeWhileметоди) у моїй серії блогів Edulinq .


Джон, чи не ризикує це виключення, якщо "послідовність" має значення Null?
WEFX,

@WEFX: Ну, ми не маємо уявлення, sequenceможе це бути законно nullчи ні. Імовірно, ОП може з цим впоратися самостійно - це насправді не є частиною питання ...
Джон Скіт,

5

Ви можете використовувати Enumerable.Skip щоб пропустити деякі елементи і почати там.

Наприклад:

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

Однак, якщо ви пишете дерево, вам може знадобитися вказати учасника в самому елементі дерева, який поверне новий, IEnumerable<T>який буде перераховувати звідти вниз. Це могло б бути більш корисним у довгостроковій перспективі.


Щось на зразок IEnumerable<T> SubTree(rootIndex)? Гарний дзвінок!
Dan J

Дякую за відповідь, skip виглядає багатообіцяючим, читаючи інформацію MSDN про skip, я дійшов висновку, що, можливо, можна написати метод StartFrom (це дерево IEnumerable <MyTree>, елемент MyTreeElement), який би був методом розширення для IEnumerable <MyTree>, який поверне IEnumerable <MyTreeElement>, з якого я повинен почати ітерацію. Тоді, можливо, я міг би використати цей метод як foreach (елемент var у дереві.StartFrom (someElement))).
пекло

@inferno: Так, ти легко міг би це зробити. Однак я просто додав би метод / властивість до MyTreeElement, що було більше схоже на:, IEnumerable<MyTreeElement> Childrenтак що ви могли б просто зробити: foreach(var item in someElement.Children)- набагато зрозуміліше, ніж використання методів розширення IMO.
Рід Копсі,

-1

Foreach буде переглядати вашу колекцію способом, визначеним вашою реалізацією IEnumerable . Отже, хоча ви можете пропустити елементи (як було запропоновано вище), ви все одно технічно перебираєте елементи в тому ж порядку.

Не впевнені, чого ви намагаєтесь досягти, але ваш клас може мати кілька IEnumerableвластивостей, кожне з яких перераховує елементи в певному порядку.


-1

Якщо ви хочете пропустити читання рядків у DataGridView, спробуйте це

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

Якщо ви хочете скопіювати вміст одного DataGridViewв інший, пропускаючи рядки, спробуйте це,

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;
}

це копіює вміст з одного DataGridViewна інший, пропускаючи 3 рядки.


Це не відповідає на запитання, яке було задано - у питанні взагалі не згадується DataGridView(або навіть про структуру інтерфейсу користувача).
NightOwl888,

@ NightOwl888 на це відповіли, оскільки питання стосувалося пропуску деяких ітерацій та ітерації після цього у циклі foreach. У моєму прикладі я просто використовував Skip () для застосування на DataGridView.
Джунд-хан Момін,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.