linq contains string comparison. IEqualityComparer - c#

I want to know if a determind string is in a string list, with the StringComparison.InvariantCultureIgnoreCase criteria. So I tried something like:
bool isInList = _myList.Contains(toFindString, StringComparison.InvariantCultureIgnoreCase);
Or:
bool isInList = _myList.Contains(listElement => listElement .Equals(toFindString,StringComparison.InvariantCultureIgnoreCase));
But, the Contains method does not contain the Func<TSource, bool> predicate overload which I think is the cleanest for this case. The Where or the Count method for example got it.
Overload method signature for Count:
public static int Count<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
Specific application for my case:
int foundCount = _myList.Count(listElement => listElement.Equals(toFindString, StringComparison.InvariantCultureIgnoreCase));
What would be the cleanest way to add the StringComparison.InvariantCultureIgnoreCase criteria to the linq Contains current overload with the IEqualityComparer that is this one public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer);?

You've got several options.
The first is to use Enumerable.Any, and test each element using the string.Equals overload which takes a StringComparison:
bool isInList = _myList.Any(x => string.Equals(x, "A", StringComparison.InvariantCultureIgnoreCase));
(It's safer to use the static string.Equals(string, string) where possible, as it's safe to either argument being null).
Linq also provides an overload of Contains which takes an IEqualityComparer<T>, which you can pass StringComparer.InvariantCultureIgnoreCase to:
bool isInList = _myList.Contains("A", StringComparer.InvariantCultureIgnoreCase);
See here.

Either use StringComparer.InvariantCultureIgnoreCase
bool isInList = _myList.Contains(toFindString, StringComparer.InvariantCultureIgnoreCase);
or use Any with StringComparison:
bool isInList = _myList.Any(s => s.Equals(toFindString,StringComparison.InvariantCultureIgnoreCase));
the latter has a problem if there are null-strings in the list, so you could use string.Equals.
Note that both ways are not suppported with Linq-To-Entities.

Related

Why does IEnumerable's Where pass first argument as "this"

I've just started to study on LINQ. The following example uses Where which is one of the standard query operators.
string[] names = { "Tom", "Dick", "Harry" };
IEnumerable<string> filteredNames = System.Linq.Enumerable.Where(names, n => n.Length >= 4);
I did some research on how it works and found this source:
public static partial class Enumerable
{
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
if (source is Iterator<TSource>) return ((Iterator<TSource>)source).Where(predicate);
if (source is TSource[]) return new WhereArrayIterator<TSource>((TSource[])source, predicate);
if (source is List<TSource>) return new WhereListIterator<TSource>((List<TSource>)source, predicate);
return new WhereEnumerableIterator<TSource>(source, predicate);
}
/* ... */
}
I don't understand why its first parameter, this IEnumerable<TSource> source, is prefixed with the this keyword. I know that extension methods allow an existing type to be extended with new methods without
altering the definition of the original type and that the type
of the first parameter will be the type that is extended.
Can you explain its logic beneath?
Because it is an Extension Method.
So that instead of
IEnumerable<string> filteredNames = System.Linq.Enumerable.Where(names, n => n.Length >= 4);
You can also use it like:
IEnumerable<string> filteredNames = names.Where(n => n.Length >= 4);
The Reason it is an extension method is that IEnumerable, List, ... existed long before Linq (which was introduced in .Net 3.5) and its job is just to extend finding, filtering, ordering, ... them. So it is logical to have it as an Extention method rather than a separate library. And also consider that this way you can use chaining, which woudln'd be possible if it wasn't an extension:
name.Where(x => x.Length > 4).Select(x => x.Substring(4));
Compare it to:
System.Linq.Enumerable.Select(System.Linq.Enumerable.Where(name, x => x.Length > 4), x => x.Substring(4));
And this is only a very simple one, consider how dirty it gets with larger, complex queries.
Since it's an Extension Method. It means that Where is not a method on IEnumerable but when you reference Linq namespace ,Where method is added to IEnumerable.
for more info read this :
Extension Methods
First of all, The simple answer is because it is an extension method. The definition of extension method is that Their first parameter specifies which type the method operates on, and the parameter is preceded by the this modifier.
Secondly, I disagree Ashkan Mobayen Khiabani's answers last part. you must have a look fluent implementation without extension method.

FindAll - Predicate<TSource> vs Func<TSource, bool>

I am struggling to understand why does not List<T>FindAll(...) method accepts Func<TSource, bool> but instead insists on accepting Predicate<TSource>.
So when I have a List of books and I want to get only books, which are cheaper than 10. This code runs just fine.
Predicate<Book> CheapBooksPredicate = b => b.Price < 10;
var cheapBooksPredicate = books.FindAll(CheapBooksPredicate);
But when I change Predicate<TSource> to Func<TSource, bool>
Func<Book, bool> CheapBooksFunc = b => b.Price < 10;
var cheapBooksFunc = books.FindAll(CheapBooksFunc);
I am getting error:
Argument 1: cannot convert from 'System.Func' to 'System.Predicate'
What Am I missing here ? When both Func<TSource, bool> and Predicate<TSource> are predicates. Predicate<TSource> should be specialized version of a Func that takes and evaluates a value against a set of criteria and returns a boolean, thus I though, that they can replace each other in terms of usage.
They have the same signature, but they are fundamentally different types and cannot be cast as a reference-preserving conversion. Since FindAll wants a Predicate<T>: use Predicate<T>.
Would it be nice if they were castable like this? Maybe, but it would require CLR and language changes, and is unlikely to happen.
You can use the following Extension method to convert Func<T, bool> to Predicate<T>
static Predicate<T> FuncToPredicate<T>(Func<T, bool> func)
{
return new Predicate<T>(func);
}
Reference

Linq: Extension method on IEnumerable to automatically do null-checks when performing selects

When performing a Select on an IEnumerable I believe it is good practice to check for null references, so I often have a Where before my Select like this:
someEnumerable.Where(x => x != null).Select(x => x.SomeProperty);
This gets more complicated when accessing sub-properties:
someEnumerable.Where(x => x != null && x.SomeProperty != null).Select(x => x.SomeProperty.SomeOtherProperty);
To follow this pattern I need to do a lof of calls to Where. I would like to create an extension method on IEnumerable that perform such null-checks automatically depending on what is referenced in the Select. Like this:
someEnumerable.SelectWithNullCheck(x => x.SomeProperty);
someEnumerable.SelectWithNullCheck(x => x.SomeProperty.SomeOtherProperty);
Can this be done? Is it fx. possible to retrieve the selected properties from the selector parameter when creating an extension method such as this?
public static IEnumerable<TResult> SelectWithNullCheck<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
return source.Where(THIS IS WHERE THE AUTOMATIC NULL-CHECKS HAPPEN).Select(selector);
}
EDIT: I use C# 5.0 with .NET Framework 4.5
As you are using C# 5.0 you can write your extension method the following way:
public static IEnumerable<TResult> SelectWithNullCheck<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TResult> selector)
{
return source.Where(x => x != null).Select(selector).Where(x => x != null);
}
Before and after the projection (Select call) to apply a check that the result is not null.
Then usage will be:
someEnumerable.SelectWithNullCheck(x => x.SomeProperty)
.SelectWithNullCheck(y => y.SomeOtherProperty);
Notice that the type of item in each call is different.
If you do want it similar to this:
someEnumerable.SelectWithNullCheck(x => x.SomeProperty.SomeOtherProperty);
Then you'd need to go with #Treziac's suggestion and use the ?. operator (introduced in C# 6.0) and then filter nulls out:
public static IEnumerable<TResult> SelectWithNullCheck<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
return source.Select(selector).Where( x=> x != null);
}
someEnumerable.SelectWithNullCheck(x => x?.SomeProperty?.SomeOtherProperty);
You can use Expression based solution. Below is basic and workable solution for field / property chain call. It will work for very deep call chains. It is not perfect. For example it won't work if there is method call in the chain (obj.Prop1.MethodCall().Prop2).
Expression based solutions are in general slower, because of the need to compile the lambda expression to delegate, which should be taken in consideration.
Performance stats:
Testes with collection of 200k objects with nested call level of 2 (obj.Prop1.Prop2) where all objects fail for the condition.
LINQ Where with C# 6 ?. operator : 2 - 4 ms
Exception based (try / catch): 14,000 - 15,000 ms
Expression based: 4 - 10 ms
NOTE: The expression based solution will add overhead of several ms for every call, this number won't depend on the collection size, because the expression will be compiled for every call which is an expensive operation. You can think for cache mechanism if you are interested.
Source for expression based solution::
public static IEnumerable<T> IgnoreIfNull<T, TProp>(this IEnumerable<T> sequence, Expression<Func<T, TProp>> expression)
{
var predicate = BuildNotNullPredicate(expression);
return sequence.Where(predicate);
}
private static Func<T, bool> BuildNotNullPredicate<T, TProp>(Expression<Func<T, TProp>> expression)
{
var root = expression.Body;
if (root.NodeType == ExpressionType.Parameter)
{
return t => t != null;
}
var pAccessMembers = new List<Expression>();
while (root.NodeType == ExpressionType.MemberAccess)
{
var mExpression = root as MemberExpression;
pAccessMembers.Add(mExpression);
root = mExpression.Expression;
}
pAccessMembers.Reverse();
var body = pAccessMembers
.Aggregate(
(Expression)Expression.Constant(true),
(f, s) =>
{
if (s.Type.IsValueType)
{
return f;
}
return Expression.AndAlso(
left: f,
right: Expression.NotEqual(s, Expression.Constant(null))
);
});
var lambda = Expression.Lambda<Func<T, bool>>(body, expression.Parameters[0]);
var func = lambda.Compile();
return func;
}
This is how is used:
var sequence = ....
var filtered = sequence.IgnoreIfNull(x => x.Prop1.Prop2.Prop3 ... etc);
Why not using ?. operator ?
someEnumerable.Where(x => x?.SomeProperty != null).Select(x => x.SomeProperty.SomeOtherProperty);
(note that this may return null values)
or
someEnumerable.Select(x => x?.SomeProperty?.SomeOtherProperty).Where(x => x != null);
(this will not return any null values)
It's not really good or bad practice, it depends of what you want in your return
Another option is to split the selection null check into a custom operator (e.g. WhereNotNull). Combine this with the ?. operator, solves your problem in an imho very expressive way.
public static IEnumerable<TSource> WhereNotNull<TSource>(this IEnumerable<TSource> source)
{
return source.Where(x=> x != null);
}
This allows you to write:
someEnumerable.Select(x => x?.SomeProperty?.SomeOtherProperty)
.WhereNotNull();
If not you could always chain the selects (for version prior to C# 6):
someEnumerable.Select(x => x.SomeProperty)
.Select(x => x.SomeOtherProperty)
.WhereNotNull();
Given you absolutely want to access x.SomeProperty.SomeOtherProperty the last option would be to catch the NullReferenceException.
public static IEnumerable<TResult> SelectWithNullCheck<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
return source.Select(x =>
{
try
{
return selector(x);
}
catch(NullReferenceException ex)
{
return default(TResult);
}
})
.Where(x=> default(TResult) != x);
}

Two candidates in method Enumerable.Where

Has anyone encountered this problem? I have two same candidates to method Enumerable.Where
And what is the Func'2 and Func'3?
When i trying to filter enumerable
var subItems = itemsToShow.Where(item => item.Visible);
I have an error:
Cannot resolve method 'Where(lambda expression)', candidates are
System.Collection.Generic.IEnumerable<T> Where<T>(this System.Collection.Generic.IEnumerable<T>, System.Func'2) (in calss Enumerable)
System.Collection.Generic.IEnumerable<T> Where<T>(this System.Collection.Generic.IEnumerable<T>, System.Func'3) (in calss Enumerable)
On .Net 3.5 this work perfect
A quick look at the MSDN tells you that there are in fact two overloads.
One just filters based on a predicate, and the second overload also takes the index of the item in the enumeration into account.
Func'3 and Func'2 meens that it is a generic class with 2 and 3 type parameters.
I assume that first is for Func<T, bool> where T is your earlier defined type.
and Func<T, int, bool> the same plus indexer.
Func<T, int, bool> - it is a predicate that accepts two arguments of types T and int and returns bool.
Just build the solution and see the detailed error. Mine was a nullable boolean.
It happened to me because I was trying to use .Contains on a List type, while what I needed was .Any
for example
var myObjectsList = new List<MyClass>();
// instead of this
myObjectList.Contains(x => x.Id == 1)
// use this
myObjectList.Any(x => x.Id == 1)
Try casting to an IQueryable. Like so: itemsToShow.AsQueryable()

ascending/descending in LINQ - can one change the order via parameter?

I have a method which is given the parameter "bool sortAscending". Now I want to use LINQ to create sorted list depending on this parameter. I got then this:
var ascendingQuery = from data in dataList
orderby data.Property ascending
select data;
var descendingQuery = from data in dataList
orderby data.Property descending
select data;
As you can see, both queries differ only in "ascending" resp. "descending". I'd like to merge both queries, but I don't know how. Does anyone have the answer?
You can easily create your own extension method on IEnumerable or IQueryable:
public static IOrderedEnumerable<TSource> OrderByWithDirection<TSource,TKey>
(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
bool descending)
{
return descending ? source.OrderByDescending(keySelector)
: source.OrderBy(keySelector);
}
public static IOrderedQueryable<TSource> OrderByWithDirection<TSource,TKey>
(this IQueryable<TSource> source,
Expression<Func<TSource, TKey>> keySelector,
bool descending)
{
return descending ? source.OrderByDescending(keySelector)
: source.OrderBy(keySelector);
}
Yes, you lose the ability to use a query expression here - but frankly I don't think you're actually benefiting from a query expression anyway in this case. Query expressions are great for complex things, but if you're only doing a single operation it's simpler to just put that one operation:
var query = dataList.OrderByWithDirection(x => x.Property, direction);
In terms of how this is implemented, this changes the method - from OrderBy/ThenBy to OrderByDescending/ThenByDescending. However, you can apply the sort separately to the main query...
var qry = from .... // or just dataList.AsEnumerable()/AsQueryable()
if(sortAscending) {
qry = qry.OrderBy(x=>x.Property);
} else {
qry = qry.OrderByDescending(x=>x.Property);
}
Any use? You can create the entire "order" dynamically, but it is more involved...
Another trick (mainly appropriate to LINQ-to-Objects) is to use a multiplier, of -1/1. This is only really useful for numeric data, but is a cheeky way of achieving the same outcome.
What about ordering desc by the desired property,
blah = blah.OrderByDescending(x => x.Property);
And then doing something like
if (!descending)
{
blah = blah.Reverse()
}
else
{
// Already sorted desc ;)
}
Is it Reverse() too slow?
In addition to the beautiful solution given by #Jon Skeet, I also needed ThenBy and ThenByDescending, so I am adding it based on his solution:
public static IOrderedEnumerable<TSource> ThenByWithDirection<TSource, TKey>(
this IOrderedEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
bool descending)
{
return descending ?
source.ThenByDescending(keySelector) :
source.ThenBy(keySelector);
}

Categories

Resources