I can never remember. How do i process each element in a string? I want to write
stringblah.Split('/n', Split('\n', StringSplitOptions.RemoveEmptyEntries))
.Each(s=>s.Trim());
Are you looking for Select?
var items = stringblah.Split(new[] {'\n'}, StringSplitOptions.RemoveEmptyEntries)
.Select(s => s.Trim());
// ...
foreach (var item in items)
{
Console.WriteLine(item);
}
You can always make your own extension method:
public static class MyExtensions
{
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (T element in source) action(element);
}
}
However, I would warn that most people would say you shouldn't do this. Using a traditional foreach loop is considered the better practice.
Related
Goal: ForEach extension masking Select.
Reason: Select allows for method chaining while foreach does not; ForEach is more readable than Select.
The problem I'm running into is that I'm getting this error.
The type arguments for method 'System.Linq.Enumerable.Select(System.Collections.Generic.IEnumerable, System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly. (CS0411)
public static void ForEach<T>(this IEnumerable<T> elements, Action<T, int> action)
{
elements.Select((elem, i) => action(elem, i));
}
I've tried doing elements.Select((T elem, int i) => action(elem, i)); but that produces the same error.
I've also attempted using Func instead of Action but there doesn't seem to be any way to use void for the return (which is what Action is for anyways). If I define the method to take a Func instead of Action then when I try to call it using Action I get the same error.
public static IEnumerable<TOut> ForEach<TIn, TOut>(this IEnumerable<TIn> elements,
Func<TIn, int, TOut> function)
{
return elements.Select((elem, i) => function(elem, i))
.ToList();
}
I don't understand which arguments cannot be inferred. There are ways I could get around this (using a for loop or foreach loop and track the index), but I would still like to figure out why this won't work.
Edit: I also just realized my other ForEach for Action (no index) also gets this error when I switch from a foreach loop to calling Select.
public static void ForEach<T>(this IEnumerable<T> elements, Action<T> action)
{
elements.ToList().Select((T elem) => action(elem));
/*foreach (var elem in elements)
action(elem);*/
}
The problem is that Select expects a return value (you're projecting an object into something else) - of which your Action is returning void. void can't be converted into T, which is what Select is expecting.
The simple fix is to ensure something is returned at the end of your select function:
public static void ForEach<T>(this IEnumerable<T> elements, Action<T, int> action)
{
elements.Select((elem, i) =>
{
action(elem, i);
return elem;
}).Count();
}
The action is called, and the collection continues to be enumerated. We need to call Count because nothing will actually happen until we attempt to get a value from each enumeration (thank you Jon Skeet!)
Note that this isn't how Select should be used - the OP specifically asked why/how to make it work with it.
To do this properly, as mentioned in the comments, the solution is to use an actual foreach loop with a counter:
public static void ForEach<T>(this IEnumerable<T> elements, Action<T, int> action)
{
int count = 0;
foreach (var item in elements)
{
action(item, count++);
}
}
If you want to allow method chaining, you can do it this way:
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> elements, Action<T, int> action)
{
int count = 0;
foreach (var item in elements)
{
action(item, count++);
yield return item;
}
}
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var element in source) action(element);
return source;
}
The code above gives me a warning that source is potentially iterated multiple times, but is it really? It's iterated once in the foreach statement, but how does the return statement make it iterated again?
The return doesn't iterate the enumerable again. But you are returning it, and since the only way you could possibly do ANYTHING with this result is to iterate it elsewhere, this warning is given.
Why return it if you are not going to iterate it later?
In the current code you show there is only one iteration. It is very well possible that you are enumerating it again somewhere else since the same enumerable is returned. That is what the warning is telling you.
My personal preference would be to change the return type of the ForEach to void, and add a second one that returns the result of a Func<T, R>.
So:
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var element in source)
action(element);
}
And:
public static IEnumerable<R> ForEach<T, R>(this IEnumerable<T> source, Func<T, R> action)
{
foreach (var element in source)
yield return action(element);
}
That way you are never accidentally reusing the same enumerable and you are making it lazy: it won't execute before you actually call the enumerable.
I'm trying to do the reverse of the Select method: to project bunch of items based on their Id,
I'm thinking of Where so I would make something like this:
db.Books.Where(b => b.Id==1 || b.Id==3 || b.Id==5)
but if I have a long list of Id, or if I want to search by Title , it will be very painful code,
so is there a way to retrieve a list of items based on a group of values (like SQL: WHERE id IN..)
string[] bookNames = { "BookName1", "BookName2" };
db.Books.Where(b => bookNames.Contains(b.Name));
The solutions listed above all work - Dispersia's LINQ query's really nice actually.
One more possibility to keep in mind for what it's worth: you can always write your own LINQ-like extension methods. Here are a couple I put together for what they're worth. (I don't claim that these are actually better than the other solutions or that you'd necessarily want to use them instead - they're just something to keep in mind for reference in case you want to do something similar in the future).
Note that the compiler'll even allow you to add them to the System.Linq namespace if you want, but you could definitely argue about whether that's a good practice or not.
namespace System.Linq
{
public static class LinqExtensions
{
// This one's more or less like "Contains" except for the "params" part
// Example: book.Id.In(1, 2, 3, 4, 5)
public static bool In<T>(this T item, params T[] list)
{
foreach (T args in list)
{
if (args.Equals(item))
{
return true;
}
}
return false;
}
// Same idea as above except using an equality tester
// Example: listBooks.Where(book => book.In((bk, id) => bk.Id == id, 1, 2, 3, 4, 5));
public static bool In<T, U>(this T item, Func<T, U, bool> equalitytester, params U[] list)
{
foreach (U arg in list)
{
if (equalitytester(item, arg))
{
return true;
}
}
return false;
}
// See if any item in the first list is also in the second list
public static bool In<T, U>(this IEnumerable<T> list, Func<T, U, bool> equalityTester, params U[] argList)
{
foreach (T item in list)
{
foreach (U arg in argList)
{
if (equalityTester(item, arg))
{
return true;
}
}
}
return false;
}
}
}
You can declare a List<integer> or an array of integers. Add values to it. AND USE Contains method
Where(b => lst.Contains(b))
I' wrote an extension method, and it works great as I wanted, with any type and any member:
public static IEnumerable<TSource> In<TSource, TMember>(this IEnumerable<TSource> source,
Func<TSource, TMember> identifier, params TMember[] values) =>
source.Where(m => values.Contains(identifier(m)));
You can call it like this:
var myBooks = Books.In(b => b.Id, 1, 3, 5, 8, 11, 22);
For my future needs, I uploaded it to NuGet
Install-Package Mshwf.NiceLinq
Given an existing ICollection<T> instance (e.g. dest) what is the most efficient and readable way to add items from an IEnumerable<T>?
In my use case, I have some kind of utility method Collect(IEnumerable items) which returns a new ICollection with the elements from items, so I am doing it in the following way:
public static ICollection<T> Collect<T>(IEnumerable<T> items) where T:ICollection<T>
{
...
ICollection<T> dest = Activator.CreateInstance<T>();
items.Aggregate(dest, (acc, item) => { acc.Add(item); return acc; });
...
return dest;
}
Question: Is there any “better” way (more efficient or readable) of doing it?
UPDATE: I think the use of Aggregate() is quite fluent and not so inefficient as invoking ToList().ForEach(). But it does not look very readable. Since nobody else agrees with the use of Aggregate() I would like to read your reasons to NOT use Aggregate() for this purpose.
Just use Enumerable.Concat:
IEnumerable<YourType> result = dest.Concat(items);
If you want a List<T> as result use ToList:
List<YourType> result = dest.Concat(items).ToList();
// perhaps:
dest = result;
If dest is actually already a list and you want to modify it use AddRange:
dest.AddRange(items);
Update:
if you have to add items to a ICollection<T> method argument you could use this extension:
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> seq)
{
List<T> list = collection as List<T>;
if (list != null)
list.AddRange(seq);
else
{
foreach (T item in seq)
collection.Add(item);
}
}
// ...
public static void Foo<T>(ICollection<T> dest)
{
IEnumerable<T> items = ...
dest.AddRange(items);
}
Personally I'd go with #ckruczek's comment of a foreach loop:
foreach (var item in items)
dest.Add(item);
Simple, clean, and pretty much everybody immediately understands what it does.
If you do insist on some method call hiding the loop, then some people define a custom ForEach extension method for IEnumerable<T>, similar to what's defined for List<T>. The implementation is trivial:
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
if (source == null) throw new ArgumentNullException(nameof(source));
if (action == null) throw new ArgumentNullException(nameof(action));
foreach (item in source)
action(item);
}
Given that, you would be able to write
items.ForEach(dest.Add);
I don't see much benefit in it myself, but no drawbacks either.
We actually wrote an extension method for this (along with a bunch of other ICollection extension methods):
public static class CollectionExt
{
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> source)
{
Contract.Requires(collection != null);
Contract.Requires(source != null);
foreach (T item in source)
{
collection.Add(item);
}
}
}
So we can just use AddRange() on an ICollection():
ICollection<int> test = new List<int>();
test.AddRange(new [] {1, 2, 3});
Note: If you wanted to use List<T>.AddRange() if the underlying collection was of type List<T> you could implement the extension method like so:
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> source)
{
var asList = collection as List<T>;
if (asList != null)
{
asList.AddRange(source);
}
else
{
foreach (T item in source)
{
collection.Add(item);
}
}
}
Most efficient:
foreach(T item in itens) dest.Add(item)
Most readable (BUT inefficient because it is creating a throwaway list):
items.ToList().ForEach(dest.Add);
Less readable, but Not so inefficient:
items.Aggregate(dest, (acc, item) => { acc.Add(item); return acc; });
items.ToList().ForEach(dest.Add);
If you dont want to create a new collection instance, then create an extension method.
public static class Extension
{
public static void AddRange<T>(this ICollection<T> source, IEnumerable<T> items)
{
if (items == null)
{
return;
}
foreach (T item in items)
{
source.Add(item);
}
}
}
Then you can edit your code like this:
ICollection<T> dest = ...;
IEnumerable<T> items = ...;
dest.AddRange(items);
I am using .Net 4.5. How do I define a generci action that takes in another generic action as a parameter?
When I try the following, the compiler seems to interpret T as an actual type and complains that its definitions is not found:
public static Action<Action<T>, IEnumerable<T>> RepeatForEach = (a, x) =>
{
foreach (T t in x)
{
a.Invoke(t);
}
};
I tried the following, none of which worked:
Action<T><Action<T>>
Action<Action<T>><T>
Action<Action<T>> where T : object
I dont think it is possible to create a generic type based upon another generic. As said by sstan:
"Even generic types need to be declared somewhere."
Instead you should try another approach, what about you create an extention method instead? This is my sugestion:
public static void RepeatForEach(this Action<T> action, IEnumerable<T> itens)
{
foreach (T t in x)
{
a.Invoke(t);
}
}
So you can call it by:
Action<int> t = (int i)=> Console.WriteLine(i);
t.RepeatForEach(myitens)
I'm afraid that C# doesn't support this level of genericity. You will have to make the enclosing scope generic.
Either have a class:
public static class RepeatForEach<T>
{
public static Action<Action<T>, IEnumerable<T>> Action = (action, enumerable)
{
foreach (var element in enumerable)
{
action.Invoke(element);
}
}
}
Or have a method returning the action:
public static class MyClass
{
public static Action<Action<T>, IEnumerable<T>> GetRepeatForEachAction<T>()
{
return (action, enumerable) =>
{
foreach (var element in enumerable)
{
action.Invoke(element);
}
}
}
}
I'd also like to put forth an idea that having something do foreach on IEnumerable is generally a very bad idea. The reason for that would be to achieve side effects and IEnumerable is not built for that.
Imagine having an IEnumerable created via yield return. Then your action might not affect any of the elements (as those may be thrown away and recreated upon enumeration).