Проблема перечисления, любой способ избежать двух петель?

StackOverflow https://stackoverflow.com/questions/3069066

  •  28-09-2019
  •  | 
  •  

Вопрос

У меня есть третьей сторонней API, у которого есть класс, который возвращает перечислитель для разных предметов в классе.

Мне нужно удалить элемент в этом перечислении, поэтому я не могу использовать «для каждого». Только опция, о которой я могу придумать, это получить счетчик, итерацией по поводу Enum, а затем запустить нормальный цикл для удаления элементов.

Кто-нибудь знает о способе избежать двух петель?

Спасибо

Обновить Извините за путаницу, но Андрей ниже в комментариях правильно.

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

for each (myProperty in MyProperty)
{
if (checking some criteria here)
   MyProperty.Remove(myProperty)
}

MyProperty - это третий класс, который реализует перечисление и метод удаления.

Это было полезно?

Решение

Общий шаблон - сделать что-то вроде этого:

List<Item> forDeletion = new List<Item>();

foreach (Item i in somelist)
   if (condition for deletion) forDeletion.Add(i);

foreach (Item i in forDeletion)
   somelist.Remove(i); //or how do you delete items 

Другие советы

Петля через него один раз и создайте второй массив, который содержит элементы, которые не должны быть удалены.

Если вы знаете, это коллекция, вы можете пойти с возвратой для:

for (int i = items.Count - 1; i >= 0; i--)
{
   items.RemoveAt(i);
}

В противном случае вам придется делать две петли.

Вы можете создать что-то вроде этого:

      public IEnumerable<item> GetMyList()
    {
        foreach (var x in thirdParty )
        {
            if (x == ignore)
                continue;
            yield return x;
        }

    }

Мне нужно удалить элемент в этом перечислителе

Пока это один предмет, который не проблема. Правило это то, что вы не может продолжаться Итерацию после модификации коллекции. Таким образом:

foreach (var item in collection) {
    if (item.Equals(toRemove) {
        collection.Remove(toRemove);
        break;      // <== stop iterating!!
    }
}

Невозможно удалить предмет из перечислетеля. То, что вы можете сделать, это копировать или фильтровать (или оба) содержание всей последовательности перечисления. Вы можете добиться этого, используя LINQ и сделать Smthing, как это:

   YourEnumerationReturningFunction().Where(item => yourRemovalCriteria);

Можете ли вы уточнить API и вызовы API, которые вы используете?

Если вы получили IEnumerator<T> или IEnumerable<T> Вы не можете удалить любой элемент из последовательности за перечислетелем, потому что нет метода для этого. И вы, конечно, должны, конечно, не полагаться на литье полученного объекта, потому что реализация может измениться. (На самом деле хорошо спроектированная API не должна подвергать восьмо внутреннем состоянии, удерживающих внутреннее состояние.)

Если вы получаете IList<T> или что-то похожее, что вы можете просто использовать нормальный for Структура от спины к спереди и удалить предметы по мере необходимости, потому что нет итератора, которого состояние может быть повреждено. (Здесь правило о разоблачении мусорного состояния должно применяться снова - модификация возвращенной коллекции не должна меняться никакого состояния.)

IEnumerator.count () будет принимать решение во время выполнения того, что ему нужно сделать - перечислять подсчитывать или отражать, чтобы увидеть, что это коллекция и позвоните.

Мне нравится предложить Сёрд, но я беспокоюсь о том, сколько предметов мы можем говорить.

Почему бы не что-то вроде ..

 // you don't want 2 and 3
 IEnumerable<int> fromAPI = Enumerable.Range(0, 10);
 IEnumerable<int> result = fromAPI.Except(new[] { 2, 3 });

Чистый, читаемый способ сделать это выглядит следующим образом (я предполагаю, что на API стороннего контейнера здесь здесь, поскольку вы этого не указали.)

foreach(var delItem in ThirdPartyContainer.Items
                       .Where(item=>ShouldIDeleteThis(item))
                       //or: .Where(ShouldIDeleteThis)
                       .ToArray()) {
    ThirdPartyContainer.Remove(delItem);
}

Призыв к .ToArray() гарантирует, что все предметы будут удалены, были жадно кэшированы до начала итерации Foreach.

За кулисами это связано с массивом и дополнительная итерация над этим, но это вообще очень дешево, и преимущество этого метода над другими ответами на этот вопрос заключается в том, что он работает на простых перечисленных средствах и не связан с хитрыми сочетами. Трудно читать и легко исправить.

Напротив, итерацией, что в обратном направлении, в то время как не ракетная наука, гораздо более склонна к одному на одних ошибках и труднее читать; И это также опирается на внутренние части коллекции, таких как не изменяющий заказ между удалениями (например, лучше не быть двоичным кусочком, скажем). Вручную добавляя элементы, которые должны быть удалены во временный список, это просто ненужный код - вот что.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top