What difference between
FirstOrDefault(someField => someField.Name.Equals(settings.Text))
and
Where(someField => someField.Name.Equals(settings.Text)).FirstOrDefault()
?
As far as I understand in both cases Linq will run till the first occurence that suits the condition.
They result of both statements is the same. You can think of the first one as a shorter version of the second one.
The FirstOrDefault method has an overload taking in a second parameter, a Func<TSource, bool> which is the same predicate you are defining in your Where statement.
If we are talking about Linq to Objects, then there is one notable difference. Second statement
Where(someField => someField.Name.Equals(settings.Text)).FirstOrDefault()
Will create WhereEnumerableIterator internally, and then it will start enumeration and take first item:
// argument checks and collection optimizations removed
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
// it enumerates source and returns items which match predicate
return new WhereEnumerableIterator<TSource>(source, predicate);
}
public static TSource First<TSource>(this IEnumerable<TSource> source)
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
return enumerator.Current;
}
throw Error.NoElements();
}
But first statement will just take first item from source which matches predicate without creating additional enumerator:
// argument checks removed
public static TSource First<TSource>(
this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (TSource local in source)
{
if (predicate(local))
return local;
}
throw Error.NoMatch();
}
So, first one is better in terms of performance:
FirstOrDefault(someField => someField.Name.Equals(settings.Text))
Related
One of IEnumerable's overload is:
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector);
In the selector I wish to include the source. I know this sounds counter-intuitive because you provide the source to Select in the first place, but JavaScript has something similar. I would want to use it in a quick situation like this one here:
var greetings = new List<string> { "John", "Keith", "Sarah", "Matt" }.Select((name, index, source) => {
if (name == source.First())
return $"{name} (Todays Winner)";
return name;
});
The above will have an error because Select's selector parameter does not return 3 values. Just the current object, and index. I want it to include the source.
I don't want to first create the list separately and then do .first on it.
Here is how far I've gone with the extension; I'm not sure how to implement it.
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult, IEnumerable<TSource>> selector)
{
//not sure what to put in here, must be missing something simple ;(
}
Update
The above situation is just a made up example. My actual case requires using .Last() not .First() so index won't be useful since we don't know what the last index will be, as opposed to zero being first. Hence my need for the source to be passed back.
This should do it:
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TSource>, TResult> selector)
{
using (var enumerator = source.GetEnumerator()) {
for (var i = 0 ; enumerator.MoveNext() ; i++) {
yield return selector(enumerator.Current, i, source);
}
}
}
Note that you have written the wrong type for the selector parameter. It should be Func<TSource, int, IEnumerable<TSource>, TResult>, not Func<TSource, int, TResult, IEnumerable<TSource>>.
If you just want to check if an element is the first, why not just check index == 0?
var greetings = new List<string> { "John", "Keith", "Sarah", "Matt" }.Select((name, index, source) => {
if (index == 0)
return $"{name} (Todays Winner)";
return name;
});
This should work:
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, IEnumerable<TSource>, TResult> selector)
{
int index = 0;
foreach(var item in source)
{
yield return selector(item, index, source);
index++;
}
}
Let's say I have the a list of anonymous objects like this
list = [{name: "bob"},{name: "sarah"},{name: "Bob"}]
then when I do list.Distinct(), I will get [{name: "bob"},{name: "sarah"},{name: "Bob"}]
Is there a way to tell it to ignore casing on string type members and just have it return bob or Bob for the duplicate item so the result is [{name: "bob"},{name: "sarah"}]
Best I have is hacking around it using GroupBy on .name.ToLower() - but that's far from ideal.
Distinct use comparison defined of the type to detect the same object. That means it should check if they are the same reference because they are objects.
This can be checked in https://dotnetfiddle.net/h5AoUZ
In your case, there is no way for .NET to know your criteria to consider bob and Bob are the same.
One proposition for you. A new Distinct method with a function parameter:
public static IEnumerable<TSource> DistinctBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
HashSet<TKey> seenKeys = new HashSet<TKey>();
foreach (TSource element in source)
{
if (seenKeys.Add(keySelector(element)))
{
yield return element;
}
}
}
And calling
list.DistinctBy(x=>x.name.Lower())
I've been running into situations where I feel I'm lacking a LINQ extension method which effectivelly checks if there is no match of the specified predicate in a collection. There is Any and All, but if I for instance use the following code:
if (Objects.All(u => u.Distance <= 0))
This returns true if all the objects in the collection are 0 or less yards away.
if (Objects.Any(u => u.Distance <= 0))
This returns true if there is at least one object in the collection which is 0 or less yards away from me.
So far so good, both those methods make sense and the syntax for them makes sense too. Now, if I want to check if there is no object with 0 or less distance, I'd have to invert the predicate inside the All method to >= 0 instead of <= 0 or call !All(), which in some cases results in very poorly readable code.
Is there no method which effectively does Collection.None(u => u.Distance <= 0) to check if there is no object in the collection which is 0 or less yards away? It's syntactic sugar more than an actual problem, but I just have the feeling it's missing.
None is the same as !Any, so you could define your own extension method as follows:
public static class EnumerableExtensions
{
public static bool None<TSource>(this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
return !source.Any(predicate);
}
}
You can write your own Extension Method:
public static bool None(this IEnumerable<T> collection, Func<T, bool> predicate)
{
return collection.All(p=>predicate(p)==false);
}
Or on IQueryable<T> as well
public static bool None(this IQueryable<T> collection, Expression<Func<TSource, bool>> predicate)
{
return collection.All(p=> predicate(p)==false);
}
Even shorter version
static class LinqExtensions
{
public static bool None<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) => !source.Any(predicate);
}
i have the following linq extension method, which returns an IEnumerable. This means, that this piece of code ends up hitting the DB, before the rest of the linq statement has been finished.
Is it possible to refactor this so it returns an IQueryable instead?
public static IEnumerable<TSource> WhereIf<TSource>
(this IEnumerable<TSource> source, bool condition,
Func<TSource, bool> predicate)
{
return condition ? source.Where(predicate) : source;
}
How about?
var queryable = source.AsQueryable();
return condition ? queryable.Where(predicate) : queryable;
Link
How about the following:
public static IQueryable<TSource> WhereIf<TSource>
(this IQueryable<TSource> source, bool condition,
Func<TSource, bool> predicate)
{
return condition ? source.Where(predicate) : source;
}
If you change IEnumerable to IQueryable, then source.Where would also return an IQueryable when called, and seeing as source itself would be an IQueryable, the whole return statement would succeed in either case.
The IEnumerable extension method FirstOrDefault didn't exactly do as I wanted so I created FirstOrValue. Is this a good way to go about this or is there a better way?
public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, T value)
{
T first = source.FirstOrDefault(predicate);
return Equals(first, default(T)) ? value : first;
}
Your code is probably incorrect; you probably haven't considered all of the cases.
Of course, we cannot know if any code is correct or incorrect until we have a spec. So start by writing a one-line spec:
"FirstOrValue<T> takes a sequence of T, a predicate, and a value of T, and returns either the first item in the sequence that matches the predicate if there is one, or, if there is not, the stated value."
Does your attempt actually implement that spec? Certainly not! Test it:
int x = FirstOrValue<int>( new[] { -2, 0, 1 }, y=>y*y==y, -1);
this returns -1. The correct answer according to the spec is 0. The first item that matches the predicate is zero, so it should be returned.
A correct implementation of the spec would look like:
public static T FirstOrValue<T>(this IEnumerable<T> sequence, Func<T, bool> predicate, T value)
{
if (sequence == null) throw new ArgumentNullException("sequence");
if (predicate == null) throw new ArgumentNullException("predicate");
foreach(T item in sequence)
if (predicate(item)) return item;
return value;
}
Always write a spec first, even if it's only a single sentence.
default(T) will return null by default for reference types.
I would do this
public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, T value)
{
T first = source.FirstOrDefault(predicate);
return first ?? value;
}
Since this is an overload, it's worth mentioning the version with no predicate.
public static T FirstOrValue<T>(this IEnumerable<T> sequence, T value)
{
if (sequence == null) throw new ArgumentNullException("sequence");
foreach(T item in sequence)
return item;
return value;
}
Seems reasonable to me if you want to tweak the readability instead of using DefaultIfEmpty.
You could also create an override that uses a lambda if the creation of the default value is expensive, creating it only if necessary.
public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, Func<T> getValue)
{
T first = source.FirstOrDefault(predicate);
return Equals(first, default(T)) ? getValue() : first;
}