2010-11-15 3 views
11

Я с удивлением вижу, что не существует способа добавить один элемент в коллекцию IEnumerable.Каков наилучший способ добавления одного элемента в коллекцию IEnumerable?

Как добавить один элемент в коллекцию IEnumerable?

+0

возможно дубликат [Как я могу добавить элемент к IEnumerable коллекции] (HTTP : //stackoverflow.com/questions/1210295/how-can-i-add-an-item-to-a-ienumerablet-collection) – nawfal

ответ

23

Вы не можете добавлять элементы в IEnumerable, как это должно быть только для чтения. Лучше всего это либо что-то вроде:

return new List<Foo>(enumerable){ new Foo() }; 

или

return enumerable.Concat(new [] { new Foo() }); 
6

Вы можете объединить его с одноплодным массивом:

IEnumerable xs; 
xs.Concat(new[]{x}); 
19

Точка IEnumerable в том, что это только для чтения коллекции тянуть стиль. Если вы хотите, вы можете моделировать надстройку, делая что-то вроде этого:

public static IEnumerable<T> Add<T>(this IEnumerable<T> source, T additionalItem) 
{ 
    foreach(var item in source) 
    { 
     yield return item; 
    } 

    yield return additionalItem; 
} 
+2

Я смиренно предлагаю назвать этот метод «Конкат», поскольку я чувствую, что он сообщает о намерениях метод лучше, чем «Добавить», который имеет довольно сильное значение при работе с коллекцией s. – GuiSim

+3

'Append' еще лучше. Concat чувствует, что присоединяется к чему-то подобному, в то время как Add/Append чувствует себя чем-то дополнением (хотя Add чувствует себя менее ленивым). – nawfal

+0

Как-то этот метод кажется лучше, чем у Jonnii's, используя доходность кажется более естественным при работе с перечислимым –

0

IEnumerable предназначен для перебора элементов. У него не всегда есть коллекция в качестве основы. Кроме того, пока вы просматриваете коллекцию, вы не можете изменять коллекцию.

Если вам необходимо обновить свою коллекцию во время итерации по ней, вам необходимо сделать копию перед началом цикла foreach. Метод LINQ ToList() - хороший способ сделать это.

0

Может быть, не тот ответ, который вы ищете, но использование общих классов коллекций всегда, кажется, решает эти проблемы для меня. Большинство из них имеют метод .Add (T).

2

IEnumerable - это только для чтения коллекция, ICollection предоставляет изменчивую коллекцию с добавлением и удалением.

Однако вы можете создать новый IEnumerable содержат все элементы оригинала IEnumerable и на новый элемент конкатенацией 2 списка:

var newCollection = original.Concat(new[]{element}); 
6

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

Если вы хотите добавить объекты, вы должны добавить объекты в свой конкретный класс коллекции или, по крайней мере, с помощью другого интерфейса.

4

Имея в виду, что другие говорили о невозможности «добавить» к перечислимому, вы все равно можете имитировать добавление. На самом деле, я бы сказал, что вы можете «добавить» элемент в последовательность путем преобразования последовательности в новую последовательность, которая фактически «содержит» элемент (просто перебирайте новую последовательность, если вы мне не верите!) ,

Вы также можете выразить один элемент как перечислимого что-то вроде этого:

//ToEnumerable might not be the best name here 
public static IEnumerable<T> ToEnumerable<T>(this T item) 
{ 
    return Enumerable.Repeat(item,1); 
} 

или

public static IEnumerable<T> ToEnumerable<T>(this T item) 
{ 
    yield return item; 
} 

Затем вы можете «добавить» элемент в перечислимого, как это:

var items = GetSomeItems(); 

var itemsWithNewItemOnEnd = items.Concat(somenewitem.ToEnumerable()); 

var itemsWithNewItemAtStart = somenewitem.ToEnumerable().Concat(items); 

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

var itemsWithNewItemInserted = items.Take(5).Concat(somenewitem.ToEnumerable()).Concat(items.Skip(5)); 

После завершения операции (т. вы манипулировали вашу последовательность так, чтобы он «содержит», что вы хотите содержать), вы, вероятно, хотите, чтобы сделать массив или список из последовательности с помощью методов ToArray или ToList:

var itemsWithNewItemInserted = items.Take(5).Concat(somenewitem.ToEnumerable()).Concat(items.Skip(5)).ToList(); 

Теперь itemsWithNewItemInserted является список, содержащий все нужные элементы из исходного списка, с новыми элементами, вставленными в середину.

Окунитесь чересчур чересчур похожими на это (взятие, пропуски, вставка и т. Д.), Может стоить вам с течением времени, потому что каждый добавленный метод расширения (Take, Skip и т. Д.) Может привести к повторному повторению последовательности несколько раз, синтаксис синтаксиса в списках упрощает экспресс-операции, которые выглядят довольно немного запутанными с использованием традиционной итерации.

Кроме того, здесь некоторые ссылки, которые обсуждают выражения отдельных элементов, как IEnumerable:

Passing a single item as IEnumerable<T>

Is there a neater linq way to 'Union' a single item?

+0

Я думаю, что ToEnumerable (с Concat) является самым аккуратным решением. –

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