2015-05-14 2 views
-3

Каковы сценарии, в которых вы выполняете цикл от 0 до конца списка (список или Карта) и какие сценарии вы начинаете с конца до 0? Вот фрагмент кода, который выполняет итерацию по списку от 0 до конца, чтобы отфильтровать некоторые конкретные имена учеников. Предоставляет ли этот код любое исключение в любом сценарии? Выполняет ли итерирование с конца списка до нуля, делает какой-либо разницей в этом коде?Когда цикл от 0 до конца и когда цикл от конца до 0?

List<Dictionary<string, string>> allStudentsList = allStudentsArray.ToList(); 
for (int i = 0; i < allStudentsList .Count-1; i++) { 
    Dictionary<string, string> student= allStudentsList .ElementAt(i); 
    string studentName; 
    bool hasValue = studentName.TryGetValue("id", out studentName); 
    if (hasValue) { 
     if (studentName.StartsWith("John") { 
      allStudentsList.RemoveAt(i); 
      i--; 
     } 
    } 
} 
+0

Полагая это как комментарий, поскольку он не связан с вашим вопросом, но вы должны заменить elementat (i) просто индексированием в списке.ElementAt - это оператор linq, поэтому он оптимизирован для списка (и вы добавляете только служебные данные метода), либо он не имеет определенного списка, а затем вызывает значительное замедление, потому что ему нужно перебирать весь список каждый раз до индекс для поиска элемента. –

ответ

1

Прежде всего, ваш вопрос содержит семантическую ошибку. Это:

От end-1 до 0.

Если вы начинаете с end, вы сразу же получите ArgumentOutOfRangeException из спецификации метода в ElementAt.

Если вы переезжаете из справа налево, вам не придется выполнять приращение (i++) в случае hasValue верно. Просто потому, что элементы слева от индекса не сдвинуты. Таким образом, вы можете реализовать его как:

List<Dictionary<string, string>> allStudentsList = allStudentsArray.ToList(); 
for (int i = allStudentsList.Count-1; i >= 0; i--) { 
    Dictionary<string, string> student = allStudentsList.ElementAt(i); 
    string studentName; 
    bool hasValue = studentName.TryGetValue("id", out studentName); 
    if (hasValue) { 
     if (studentName.StartsWith("John") { 
      allStudentsList.RemoveAt(i); 
     } 
    } 
} 

Далее это может повлиять на производительность. Если вы удалите элемент из List<T>.RemoveAt, это означает, что все элементы справа от индекса расположены на одном месте слева. Теперь, если вы сначала удалите справа, количество элементов справа будет небольшим, и, кроме того, количество элементов, которые будут сдвинуты влево, будет меньше, если индекс расположен вблизи нуля (просто потому, что некоторые элементы уже были удалены). Но не ожидайте увеличения производительности, если hasValue редко бывает true.

В этом случае не имеет значения, выполнено ли for вперед или назад, поскольку между различными итерациями существует «общее состояние».

+2

Я должен не согласиться с вашими первыми двумя параграфами, где вы говорите, что в вопросе «вопрос содержит семантическую ошибку». ОП использует слово «конец», чтобы описать конец списка, а не как индексную переменную. В частности, OP дважды говорит «конец списка», поэтому ясно, что он (или она) не использует «конец» в качестве индекса. Поэтому sayng это должно быть «end-1», как сказать «этот поезд идет до конца - 1 трека». – RenniePet

1

И теперь я хочу предложить товарищу ответ на самый замечательный и тщательный комментарий от CommuSoft. (т.е. "не связаны", а: "параллельно .. tangental .. 'FYI' ...") *

В общемнезависимо() используется языка! ...), если вы выполняете итерирование по индексу через любой вид структуры данных, из которой вы находитесь удаление вещи, вы всегда хотите итерации "от конца до 0." (В противном случае это действительно не имеет значения ...)

Почему? Потому что, в любое время, когда вы удаляете что-либо из какой-либо коллекции, «длина» этой коллекции уменьшается на 1. Если вы повторяете от начала до конца, это не проблема: вы никогда не «пропустите что-нибудь», и вы не столкнетесь с одним и тем же элементом дважды. Оба (!) Из которых очень реальны (и, таким образом, «полностью можно избежать»), касается того, что вы путешествуете по-другому.

+0

Небольшой комментарий: это не совсем так, для * связанного списка *, итерация назад приведет к * O (n^2) *, тогда как итерация вперед дает * O (n) * временную сложность. Некоторые Iterators/Enumerators предлагают удалить функции, и в этом случае можно выполнить inline-удаление ... –

+1

Я не совсем уверен, по какой логике вы заключаете, что «итерация связанного списка вперед» и «назад» вызывает какую-либо разницу в O-стоимости вообще. (Тем не менее, я любезно признаю вашу точку зрения, без дальнейших комментариев, «несомненно, правдой»). Мои комментарии были, в частности, * специально * направлены на те случаи, когда «текущая позиция в коллекции» выражается * ordinal, * not by (как строго в случае с «связанным списком») «указателем». Поэтому я не вижу противоречия между нашими соответствующими, действительными комментариями. –

Смежные вопросы