Что лучший способ состоит в том, чтобы изменить список в 'foreach' цикле?

Присоединитесь к генератору месяцев по вашему запросу:

select to_char(to_date(mth_num, 'MM'), 'MONTH') month, nvl(cnt, 0) cnt
  from (
    select count(emp_id) as cnt, to_char(due_date, 'mm') mth_num
      from emp_request where due_date is not null
      group by to_char(due_date, 'mm')) e
  right join (
    select to_char(level, 'fm00') mth_num 
      from dual connect by level <= 12) m using (mth_num)
  order by mth_num

dbfiddle demo sup>

Генератор месяцев - это простой иерархический запрос, который дает нам 12 значений 01, 02 ... 12:

select to_char(level, 'fm00') mth_num from dual connect by level <= 12

Вы также можете использовать системные представления для получения этих чисел: [ 1114]

select to_char(rownum, 'fm00') mth_num from all_objects where rownum <= 12

или этот синтаксис:

select to_char(column_value, 'fm00') mth_num 
  from table(sys.odcivarchar2list(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12))

Лучше работать с числами, которые можно правильно отсортировать и преобразовать в названия месяцев на последнем шаге. Таким образом, у вас есть естественный месячный порядок. Если вы хотите быть уверены, что названия месяцев всегда на английском языке, не зависят от локальных настроек, используйте to_date с третьим параметром, как здесь:

select to_char(sysdate, 'month', 'nls_date_language=english') from dual

68
задан abatishchev 17 September 2014 в 23:45
поделиться

6 ответов

Коллекция, используемая в foreach, является неизменной. Это очень много задумано.

Как сказано в MSDN :

Оператор foreach используется для перебрать коллекцию, чтобы получить информация, которую вы хотите, но можете не использоваться для добавления или удаления элементов из исходной коллекции, чтобы избежать непредсказуемые побочные эффекты. Если вы необходимо добавить или удалить элементы из В исходной коллекции используйте цикл for.

Пост в ссылке , предоставленной Poko, указывает, что это разрешено в новых одновременных коллекциях.

69
ответ дан 24 November 2019 в 14:18
поделиться

Вот как вы можете это сделать (быстрое и грязное решение. Если вам действительно нужен такой вид поведения, вы должны либо пересмотреть свой дизайн, либо переопределить все члены IList и собрать список источников):

using System;
using System.Collections.Generic;

namespace ConsoleApplication3
{
    public class ModifiableList<T> : List<T>
    {
        private readonly IList<T> pendingAdditions = new List<T>();
        private int activeEnumerators = 0;

        public ModifiableList(IEnumerable<T> collection) : base(collection)
        {
        }

        public ModifiableList()
        {
        }

        public new void Add(T t)
        {
            if(activeEnumerators == 0)
                base.Add(t);
            else
                pendingAdditions.Add(t);
        }

        public new IEnumerator<T> GetEnumerator()
        {
            ++activeEnumerators;

            foreach(T t in ((IList<T>)this))
                yield return t;

            --activeEnumerators;

            AddRange(pendingAdditions);
            pendingAdditions.Clear();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ModifiableList<int> ints = new ModifiableList<int>(new int[] { 2, 4, 6, 8 });

            foreach(int i in ints)
                ints.Add(i * 2);

            foreach(int i in ints)
                Console.WriteLine(i * 2);
        }
    }
}
4
ответ дан 24 November 2019 в 14:18
поделиться

Сделайте копию перечисления, используя в этом случае метод расширения IEnumerable, и перечислите его. Это добавит копию каждого элемента в каждом внутреннем перечисляемом для этого перечисления.

foreach(var item in Enumerable)
{
    foreach(var item2 in item.Enumerable.ToList())
    {
        item.Add(item2)
    }
}
15
ответ дан 24 November 2019 в 14:18
поделиться

Вы действительно должны использовать для () вместо foreach () в этом случае.

0
ответ дан 24 November 2019 в 14:18
поделиться

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

Цикл для является хорошей альтернативой, но если ваша коллекция IEnumerable не реализует ICollection , это невозможно.

Либо:

1) Сначала скопируйте коллекцию. Перечислите скопированную коллекцию и измените исходную коллекцию во время перечисления. (@tvanfosson)

или

2) Вести список изменений и фиксировать их после перечисления.

1
ответ дан 24 November 2019 в 14:18
поделиться

Как уже упоминалось, но с примером кода:

foreach(var item in collection.ToArray())
    collection.Add(new Item...);
8
ответ дан 24 November 2019 в 14:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: