开发者

What is the best wayto add single element to an IEnumerable collection?

I'm surprised to see that there does not appear to be a method to add a single element to an IEnumerable collection.

How can I add a single element to 开发者_StackOverflow社区an IEnumerable collection?


You can't really add elements to an IEnumerable as it's supposed to be read only. Your best bet is either something like:

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

or

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


The point of IEnumerable is that it's a readonly pull style collection. If you want, you can simulate an add by doing something like this:

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

   yield return additionalItem;
}


I'd like to point out to some of the other answers here that IEnumerable is not a read only collection, It is not a collection at all. It is an interface that defines how a collection can be iterated over.

If you want to be adding objects then you should be adding the objects to your concrete collection class or at least using a different interface.


You can concatenate it with a singleton array:

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


Keeping in mind what others have said about not really being able to "add" to an enumerable, you can still simulate adding. In fact, I would argue that you can "add" an item to a sequence by morphing the sequence into a new sequence that does in fact "contain" the item (just iterate over the new sequence if you don't believe me!).

You can also express a single item as an enumerable something like this:

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

or

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

Then you can "add" an item to an enumerable like this:

var items = GetSomeItems();

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

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

You can even insert the item into the some other location in the sequence like this (assuming you know the position after which you want to insert it):

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

After you have your operation finished (i.e. you have manipulated your sequence so that it "contains" what you want to contain), you will probably want to make an array or list out of the sequence via the ToArray or ToList methods:

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

Now itemsWithNewItemInserted is a list that contains all of the desired items from the original list, with the new items inserted in the middle.

Fooling around with sequences too much like this (taking, skipping, inserting, etc) can cost you over time because each added extension method (Take, Skip, etc) can cause the sequence to be iterated multiple times, but the list comprehension syntax does make it easier to express operations that would appear to be quite a bit more convoluted using conventional iteration.

Also, here are some links that discuss expressing single items as IEnumerable:

Passing a single item as IEnumerable<T>

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


IEnumerable is an read only collection, ICollection provides a mutable collection with Add and Remove.

However you can create a new IEnumerable contain all the items in the original IEnumerable and an new item, by concatenating 2 lists:

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


IEnumerable is designed to iterate over items. It does not always have a collection as its backing. Also, while you are looping through a collection, you cannot modify the collection.

If you need to update your collection while iterating over it, you need to make a copy before starting your foreach loop. LINQ's ToList() method is a good way to do this.


May not be the answer you're looking for, but using the generic collection classes always seem to solve these type of problems for me. Most of them have an .Add(T) method.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜