2013-05-01 4 views
-2

Мне нужно иметь дело с коллекциями данных, которые бросаются в мое приложение из источников данных из моего контроля. Некоторые из этих коллекций содержат нули, которые я бы предпочел отфильтровать, как только они попали в мой код, а не разбросали нулевой код проверки по всему месту. Я хочу сделать это в многоразовом общем виде и написал этот метод, чтобы сделать это:Удаление всех нулей из коллекций

public static void RemoveNulls<T>(this IList<T> collection) where T : class 
    { 
     for (var i = 0; i < collection.Count(); i++) 
     { 
      if (collection[i] == null) 
       collection.RemoveAt(i); 
     } 
    } 

Я знаю, что на конкретном классе List есть RemoveAll() метод, который может быть использован как:

collection.RemoveAll(x => x == null); 

Но многие типы возврата основаны на интерфейсах (IList/IList ...), а не на конкретных типах.

+1

Пожалуйста, не могли бы вы уточнить, почему вы не можете использовать 'RemoveAll'? –

+1

И в чем вопрос? –

+2

Код, который вы написали, не будет работать, поскольку удаление элемента сдвигает индексы всех последующих элементов вниз на 1. Каждый раз, когда вы удаляете нуль, ваш код пропускает проверку следующего элемента. –

ответ

14

Вместо удаления аннулирует из исходной коллекции, вы можете создать копию коллекции без нулей с помощью LINQ:

collection.Where(i => i != null).ToList(); 

Метода расширения будет работать на любой IEnumerable, в том числе IList.

+0

Зачем копировать целую коллекцию ненужно? – Jammer

+3

@Jammer, вы также можете удалить часть '.ToList()', чтобы она работала как фильтр. Если вы заботитесь о производительности, имейте в виду, что каждый RemoveAt будет перемещать все элементы списка, которые появляются после удаленной. Поэтому, если вы удалите 10 элементов из начала списка с 1000 элементами, по меньшей мере 990 элементов будут перемещены в памяти 10 раз. – alex

+1

Это может фактически повысить производительность, поскольку удаление элементов из 'IList' (по крайней мере с поддержкой массива типа« Список ») заставит копировать все последующие элементы на один слот каждый раз, когда вы это сделаете. –

4

Ваш метод не будет работать, поскольку удаление элемента приведет к уменьшению индекса всех последующих элементов. Если вы не хотите решения Linq (что кажется самым простым: см. Ответ от @alex), вы должны итератировать назад.

public static void RemoveNulls<T>(this IList<T> collection) where T : class 
{ 
    for (var i = collection.Count-1; i >= 0 ; i--) 
    { 
     if (collection[i] == null) 
      collection.RemoveAt(i); 
    } 
} 
+0

Тестирование здесь работает отлично. – Jammer

+0

Коррекция, вы правы. – Jammer

+0

«Тестирование здесь работает отлично» - попробуйте еще несколько тестовых примеров. В частности, коллекция с двумя последовательными нулями, за которыми следует непустой. – Joe

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