I'm doing a C# exercise to create an operation that takes a collection, performs a function on each object in the collection, and returns a collection of modified objects.
My code is currently as follows:
public static IEnumerable<U> Accumulate<T, U>(this IEnumerable<T> collection, Func<T, U> func)
{
IEnumerable<U> output = Enumerable.Empty<U>();
foreach (T item in collection)
{
output.Append(func(item));
}
return output;
}
This is only returning an empty collection, and I have no idea why.
I have tried creating a copy of the item in the foreach after seeing this approach in another thread, like so:
foreach (T item in collection)
{
U copy = func(item);
output.Append(copy);
}
but that didn't solve anything.
I did some research but couldn't really find any examples doing exactly what I'm trying to do here. I read some things about closure, but couldn't really understand it, as I'm new to C#.
To answer your actual question: The reason it isn't working is because
output.Append(func(item));
doesn't change output - instead, it returns a new sequence which is func(item) appended to output. Thus when you eventually return output you are just returning the original, empty sequence.
You could make yours work by this simple change:
output = output.Append(func(item));
However, this is not an efficient approach - you're much better off using yield, by modifying your method as follows:
public static IEnumerable<U> Accumulate<T, U>(this IEnumerable<T> collection, Func<T, U> func)
{
foreach (T item in collection)
{
yield return func(item);
}
}
Although note that that is more simply expressed as:
public static IEnumerable<U> Accumulate<T, U>(this IEnumerable<T> collection, Func<T, U> func)
{
return collection.Select(item => func(item));
}
But it is useful to know about how to do this with yield so that you can write solutions to more complex Linq-like problems.
Usually, when I want to achieve this kind of behaviour, I make use of C# Iterators.
They are so usefull when you want to process an iteration on some kind of data and, at each iteration, return a value that is appended to your resulting collection.
Take a look at the docs: MS Docs
I'm trying to replace usages of T[] or List<T> as function parameters and return values with more appropriate types such as IEnumerable<T>, ICollection<T> and IList<T>.
ICollection<T> from my understanding is preferrable to IList<T> where you are only needing basic/simple collection functionality (eg an enumerator and count functionality) as it provides this with the least restriction. From reading on here one of the main differentiators I thought was that ICollection<T> doesn't require that the underlying collection to be index based where IList<T> does?
In switching my List<T> references over I needed to replace a List<T>.GetRange() call and I was very surprised to find the ICollection<T>.TakeWhile() extension method which has an overload supporting selection based on index?! (msdn link)
I'm confused why this method exists on ICollection where there is nothing index based on this interface? Have I misunderstood or how can this method actually work if the underlying collection is eg a Hashset or something?
The method, like most of LINQ, is on IEnumerable<T>. Any features that just pass the indexer to the consumer (such as TakeWhile) only need to loop while incrementing a counter. Some APIs may be able to optimize using an indexer, and then it is up to them to decide whether to do that, or just use IEnumerable<T> and simply skip (etc) unwanted data.
For example:
int i = 0;
foreach(var item in source) {
if(!predicate(i++, item)) break;
yield return item;
}
Indexing can be done without collection's support of it
int i = -1;
foreach(var item in collection)
{
i++;
// item is at index i;
}
TakeWhile and other extension methods from System.Linq.Enumerable class work on all the types implementing IEnumerable<T>. They all iterate over the collection (using foreach statement) and perform appropriate actions.
Here is the implementation of the TakeWhile method, with some simplifications:
private static IEnumerable<TSource> TakeWhile<TSource>(IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (TSource item in source)
{
if (!predicate(item))
{
break;
}
yield return item;
}
}
As you see, it simply iterates over the collection, and evaluates the predicate. This is true for almost all other LINQ methods. The same will happen when you use any other collection, like HashSet<T>.
My intention is to... void Encrypt any property value in 'TSource', it could be all or some of properties depend on selector.
This is my former code:
...IEnumerable<TSource>().ForEach(delegate(TSource ts)
{
ts.prop0 = ts.prop0.Encrypt();
ts.prop1 = ts.prop1.Encrypt();
Etc...
});
IEnumerable Extension :
...ForEach<TSource>(this IEnumerable<TSource> source, Action<TSource> action)
{
foreach (TSource item in source)
action(item);
}
string Extension :
...string Encrypt(this string strPlainText)
{
if (!string.IsNullOrEmpty(strPlainText))
return SomeClass.Encrypt(strPlainText);
return strPlainText;
}
The point is how to transform all above into IEnumerable Extension just in line syntax,may or may not look like this:
//Encrypt all props. in Tsource.
...IEnumerable<TSource>().EncryptProp();
//Encrypt any prop. in Tsource. with selector property
...IEnumerable<TSource>().EncryptProp(ts => ts.prop0);
...IEnumerable<TSource>().EncryptProp(ts => ts.prop0,ts.prop1);
...IEnumerable<TSource>().EncryptProp(ts => ts.prop0,ts.prop1,Etc...);
I'd be glad to take any suggestions.
It is hard to tell exactly how this could be done because you code sample is incomplete. However, from what I can understand, you have an IEnumerable<TSource> and you would like to perform the same operation for all of the properties for all of the items in this sequence?
This requires a couple of things, first look at SelectMany. This projects each element in the source to a new sequence, flattening them all into a single sequence.
The second thing is how to create an IEnumerable<TResult> from all of the properties of each element. This is not so easy! If your Prop0, Prop1 could be stored as a dictionary that would help!
You could use reflection. Something like this:
IEnumerable<MyObject> source = ///your source
var allProperties = source.SelectMany(s =>
typeof(MyType).GetProperties().Select(p => p.GetValue(s, null));
However, as strings are immutable, if you Encrypt the resulting sequence, your source MyObject instances will not reflect this change.
If you really want to do this, store your properties in a dictionary!
If I have two sequences and I want to process them both together, I can union them and away we go.
Now lets say I have a single item I want to process between the two sequencs. I can get it in by creating an array with a single item, but is there a neater way? i.e.
var top = new string[] { "Crusty bread", "Mayonnaise" };
string filling = "BTL";
var bottom = new string[] { "Mayonnaise", "Crusty bread" };
// Will not compile, filling is a string, therefore is not Enumerable
//var sandwich = top.Union(filling).Union(bottom);
// Compiles and works, but feels grungy (looks like it might be smelly)
var sandwich = top.Union(new string[]{filling}).Union(bottom);
foreach (var item in sandwich)
Process(item);
Is there an approved way of doing this, or is this the approved way?
Thanks
One option is to overload it yourself:
public static IEnumerable<T> Union<T>(this IEnumerable<T> source, T item)
{
return source.Union(Enumerable.Repeat(item, 1));
}
That's what we did with Concat in MoreLINQ.
The new way of doing this, supported in .NET Core and .NET Framework from version 4.7.1, is using the Append extension method.
This will make your code as easy and elegant as
var sandwich = top.Append(filling).Union(bottom);
Consider using even more flexible approach:
public static IEnumerable<T> Union<T>(this IEnumerable<T> source, params T[] items)
{
return source.Union((IEnumerable<T>)items);
}
Works for single as well as multiple items.
You may also accept null source values:
public static IEnumerable<T> Union<T>(this IEnumerable<T> source, params T[] items)
{
return source != null ? source.Union((IEnumerable<T>)items) : items;
}
I tend to have the following somewhere in my code:
public static IEnumerable<T> EmitFromEnum<T>(this T item)
{
yield return item;
}
While it's not as neat to call col.Union(obj.EmitFromEnum()); as col.Union(obj) it does mean that this single extension method covers all other cases I might want such a single-item enumeration.
Update: With .NET Core you can now use .Append() or .Prepend() to add a single element to an enumerable. The implementation is optimised to avoid generating too many IEnumerator implementations behind the scenes.
My question as title above. For example
IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));
but after all it only has 1 item inside. Can we have a method like items.Add(item) like the List<T>?
You cannot, because IEnumerable<T> does not necessarily represent a collection to which items can be added. In fact, it does not necessarily represent a collection at all! For example:
IEnumerable<string> ReadLines()
{
string s;
do
{
s = Console.ReadLine();
yield return s;
} while (!string.IsNullOrEmpty(s));
}
IEnumerable<string> lines = ReadLines();
lines.Add("foo") // so what is this supposed to do??
What you can do, however, is create a new IEnumerable object (of unspecified type), which, when enumerated, will provide all items of the old one, plus some of your own. You use Enumerable.Concat for that:
items = items.Concat(new[] { "foo" });
This will not change the array object (you cannot insert items into to arrays, anyway). But it will create a new object that will list all items in the array, and then "Foo". Furthermore, that new object will keep track of changes in the array (i.e. whenever you enumerate it, you'll see the current values of items).
The type IEnumerable<T> does not support such operations. The purpose of the IEnumerable<T> interface is to allow a consumer to view the contents of a collection. Not to modify the values.
When you do operations like .ToList().Add() you are creating a new List<T> and adding a value to that list. It has no connection to the original list.
What you can do is use the Add extension method to create a new IEnumerable<T> with the added value.
items = items.Add("msg2");
Even in this case it won't modify the original IEnumerable<T> object. This can be verified by holding a reference to it. For example
var items = new string[]{"foo"};
var temp = items;
items = items.Add("bar");
After this set of operations the variable temp will still only reference an enumerable with a single element "foo" in the set of values while items will reference a different enumerable with values "foo" and "bar".
EDIT
I contstantly forget that Add is not a typical extension method on IEnumerable<T> because it's one of the first ones that I end up defining. Here it is
public static IEnumerable<T> Add<T>(this IEnumerable<T> e, T value) {
foreach ( var cur in e) {
yield return cur;
}
yield return value;
}
Have you considered using ICollection<T> or IList<T> interfaces instead, they exist for the very reason that you want to have an Add method on an IEnumerable<T>.
IEnumerable<T> is used to 'mark' a type as being...well, enumerable or just a sequence of items without necessarily making any guarantees of whether the real underlying object supports adding/removing of items. Also remember that these interfaces implement IEnumerable<T> so you get all the extensions methods that you get with IEnumerable<T> as well.
In .net Core, there is a method Enumerable.Append that does exactly that.
The source code of the method is available on GitHub..... The implementation (more sophisticated than the suggestions in other answers) is worth a look :).
A couple short, sweet extension methods on IEnumerable and IEnumerable<T> do it for me:
public static IEnumerable Append(this IEnumerable first, params object[] second)
{
return first.OfType<object>().Concat(second);
}
public static IEnumerable<T> Append<T>(this IEnumerable<T> first, params T[] second)
{
return first.Concat(second);
}
public static IEnumerable Prepend(this IEnumerable first, params object[] second)
{
return second.Concat(first.OfType<object>());
}
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, params T[] second)
{
return second.Concat(first);
}
Elegant (well, except for the non-generic versions). Too bad these methods are not in the BCL.
No, the IEnumerable doesn't support adding items to it. The alternative solution is
var myList = new List(items);
myList.Add(otherItem);
To add second message you need to -
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Concat(new[] {new T("msg2")})
I just come here to say that, aside from Enumerable.Concat extension method, there seems to be another method named Enumerable.Append in .NET Core 1.1.1. The latter allows you to concatenate a single item to an existing sequence. So Aamol's answer can also be written as
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Append(new T("msg2"));
Still, please note that this function will not change the input sequence, it just return a wrapper that put the given sequence and the appended item together.
Not only can you not add items like you state, but if you add an item to a List<T> (or pretty much any other non-read only collection) that you have an existing enumerator for, the enumerator is invalidated (throws InvalidOperationException from then on).
If you are aggregating results from some type of data query, you can use the Concat extension method:
Edit: I originally used the Union extension in the example, which is not really correct. My application uses it extensively to make sure overlapping queries don't duplicate results.
IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);
Others have already given great explanations regarding why you can not (and should not!) be able to add items to an IEnumerable. I will only add that if you are looking to continue coding to an interface that represents a collection and want an add method, you should code to ICollection or IList. As an added bonanza, these interfaces implement IEnumerable.
you can do this.
//Create IEnumerable
IEnumerable<T> items = new T[]{new T("msg")};
//Convert to list.
List<T> list = items.ToList();
//Add new item to list.
list.add(new T("msg2"));
//Cast list to IEnumerable
items = (IEnumerable<T>)items;
Easyest way to do that is simply
IEnumerable<T> items = new T[]{new T("msg")};
List<string> itemsList = new List<string>();
itemsList.AddRange(items.Select(y => y.ToString()));
itemsList.Add("msg2");
Then you can return list as IEnumerable also because it implements IEnumerable interface
Instances implementing IEnumerable and IEnumerator (returned from IEnumerable) don't have any APIs that allow altering collection, the interface give read-only APIs.
The 2 ways to actually alter the collection:
If the instance happens to be some collection with write API (e.g. List) you can try casting to this type:
IList<string> list = enumerableInstance as IList<string>;
Create a list from IEnumerable (e.g. via LINQ extension method toList():
var list = enumerableInstance.toList();
IEnumerable items = Enumerable.Empty(T);
List somevalues = new List();
items.ToList().Add(someValues);
items.ToList().AddRange(someValues);
Sorry for reviving really old question but as it is listed among first google search results I assume that some people keep landing here.
Among a lot of answers, some of them really valuable and well explained, I would like to add a different point of vue as, to me, the problem has not be well identified.
You are declaring a variable which stores data, you need it to be able to change by adding items to it ? So you shouldn't use declare it as IEnumerable.
As proposed by #NightOwl888
For this example, just declare IList instead of IEnumerable: IList items = new T[]{new T("msg")}; items.Add(new T("msg2"));
Trying to bypass the declared interface limitations only shows that you made the wrong choice.
Beyond this, all methods that are proposed to implement things that already exists in other implementations should be deconsidered.
Classes and interfaces that let you add items already exists. Why always recreate things that are already done elsewhere ?
This kind of consideration is a goal of abstracting variables capabilities within interfaces.
TL;DR : IMO these are cleanest ways to do what you need :
// 1st choice : Changing declaration
IList<T> variable = new T[] { };
variable.Add(new T());
// 2nd choice : Changing instantiation, letting the framework taking care of declaration
var variable = new List<T> { };
variable.Add(new T());
When you'll need to use variable as an IEnumerable, you'll be able to. When you'll need to use it as an array, you'll be able to call 'ToArray()', it really always should be that simple. No extension method needed, casts only when really needed, ability to use LinQ on your variable, etc ...
Stop doing weird and/or complex things because you only made a mistake when declaring/instantiating.
Maybe I'm too late but I hope it helps anyone in the future.
You can use the insert function to add an item at a specific index.
list.insert(0, item);
Sure, you can (I am leaving your T-business aside):
public IEnumerable<string> tryAdd(IEnumerable<string> items)
{
List<string> list = items.ToList();
string obj = "";
list.Add(obj);
return list.Select(i => i);
}