What is the difference between Contains and Any in LINQ?
Contains takes an object, Any takes a predicate.
You use Contains like this:
listOFInts.Contains(1);
and Any like this:
listOfInts.Any(i => i == 1);
listOfInts.Any(i => i % 2 == 0); // Check if any element is an Even Number
So if you want to check for a specific condition, use Any. If you want to check for the existence of an element, use Contains.
MSDN for Contains, Any
Contains checks if the sequence contains a specified element.
Enumerable.Any checks if element of a sequence satisfies a condition.
Consider the following example:
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
bool contains = list.Contains(1); //true
bool condition = list.Any(r => r > 2 && r < 5);
Contains cares about whether the source collection is an ICollection, Any does not.
Enumerable.Contains
http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs#f60bab4c5e27a849
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value)
{
ICollection<TSource> collection = source as ICollection<TSource>;
if (collection != null)
{
return collection.Contains(value);
}
return source.Contains<TSource>(value, null);
}
Enumerable.Any
http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs#6a1af7c3d17845e3
public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (TSource local in source)
{
if (predicate(local))
{
return true;
}
}
return false;
}
Another difference as mentioned here is on the performance
Contains is O(n) for a List and O(1) for a HashSet
Any is simply O(n)
Contains
Determines whether a sequence contains a specified element by using the default equality comparer.
Any
Determines whether a sequence contains any elements.
As for the documentation:
Can't seem to find to find any documentation on it.
All (most?) LINQ extension methods: here
Related
I'm working on a code generator that validated objects based on certain business rules. As an example, I’m curious to find out various ways below logic can be written as LINQ expression.
Assertion should evaluate to true when collection is null OR when count of "TrueAndCorrect" items is anything but 1. One possible solution is:
bool assertion = report.DeclarationOfTrusteeCollection == null
|| report.DeclarationOfTrusteeCollection.Count(f => f.FTER99.Equals("TrueAndCorrect")) != 1
Are there other ways this LINQ can be expressed as, perhaps more compact, using Any, inverting the operators, or any other?
The original code is:
bool assertion =
report.DeclarationOfTrusteeCollection == null ||
report.DeclarationOfTrusteeCollection.Count(
f => f.FTER99.Equals("TrueAndCorrect")) != 1;
There are some problems here.
First, the intention of the null check seems to be "a null collection has the same semantics as an empty collection". This is a worst-practice in C#. Never do this! If you want to represent an empty collection, make an empty collection. There's even an Enumerable.Empty helper method for you.
So, start with that; the code should be:
if (report.DeclarationOfTrusteeCollection == null)
throw some appropriate exception
or
Debug.Assert(report.DeclarationOfTrusteeCollection != null);
if the condition is impossible.
That leaves us with
bool assertion =
report.DeclarationOfTrusteeCollection.Count(
f => f.FTER99.Equals("TrueAndCorrect")) != 1;
This is bad. Suppose I show you a jar that contains some number of pennies and I ask you "is there exactly one penny in the jar?" How many pennies do you have to count before you know the answer? Your code here is counting all of them, but you could stop after two.
Enumerable gives you a method which throws if a sequence is not a singleton, but no method that tests it. Fortunately it is easy to write. The best practice here is to write a helper method that has the exact semantics you want:
static class Extensions
{
public static bool IsSingleton<T>(this IEnumerable<T> items)
{
bool seenOne = false;
foreach(T item in items)
{
if (seenOne) return false;
seenOne = true;
}
return seenOne;
}
public static bool IsSingleton<T>(
this IEnumerable<T> items, Func<T, bool> predicate) =>
items.Where(predicate).IsSingleton();
}
Done. And now your code is:
if (report.DeclarationOfTrusteeCollection == null)
throw some appropriate exception
bool assertion =
report.DeclarationOfTrusteeCollection.IsSingleton(f => ...);
Write the code so that it reads like what it is logically doing. That's the beauty and power of LINQ sequence operators.
You could use the null-propagation operator:
bool assertion = report.DeclarationOfTrusteeCollection?.Count(f => f.FTER99.Equals("TrueAndCorrect")) != 1;
Since null is not 1 this is also true if the collection is null.
It would be nice if you don't need to count the whole collection, you already know it's wrong when there's more than one matching element. But I don't know of a built-in method for that. You could write your own extension:
public static class MyExtensions
{
public static bool IsNullOrHasNotExactlyOneMatching<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
if (source == null) return true;
bool found = false;
foreach(T element in source)
{
if (!predicate(element)) continue;
if (found) return true; // this is the second match!
found = true;
}
return !found; // one match found (or not)
}
}
And use it:
bool assertion = report.DeclarationOfTrusteeCollection.IsNullOrHasNotExactlyOneMatching(f => f.FTER99.Equals("TrueAndCorrect"));
As mentioned by Rawling you could shorten the extension using Take():
public static bool IsNullOrHasNotExactlyOneMatching<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
return source?.Where(predicate).Take(2).Count() != 1;
}
or do this directly:
bool assertion = report.DeclarationOfTrusteeCollection?.Where(f => f.FTER99.Equals("TrueAndCorrect"))
.Take(2).Count() != 1;
Both versions only iterate until a second match was found (or until the end if no match was found).
I have an IEnumerable<T> and an IEnumerable<U> that I want merged into an IEnumerable<KeyValuePair<T,U>> where the indexes of the elements joined together in the KeyValuePair are the same. Note I'm not using IList, so I don't have a count or an index for the items I'm merging. How best can I accomplish this? I would prefer a LINQ answer, but anything that gets the job done in an elegant fashion would work as well.
Note: As of .NET 4.0, the framework includes a .Zip extension method on IEnumerable, documented here. The following is maintained for posterity and for use in .NET framework version earlier than 4.0.
I use these extension methods:
// From http://community.bartdesmet.net/blogs/bart/archive/2008/11/03/c-4-0-feature-focus-part-3-intermezzo-linq-s-new-zip-operator.aspx
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> func) {
if (first == null)
throw new ArgumentNullException("first");
if (second == null)
throw new ArgumentNullException("second");
if (func == null)
throw new ArgumentNullException("func");
using (var ie1 = first.GetEnumerator())
using (var ie2 = second.GetEnumerator())
while (ie1.MoveNext() && ie2.MoveNext())
yield return func(ie1.Current, ie2.Current);
}
public static IEnumerable<KeyValuePair<T, R>> Zip<T, R>(this IEnumerable<T> first, IEnumerable<R> second) {
return first.Zip(second, (f, s) => new KeyValuePair<T, R>(f, s));
}
EDIT: after the comments I'm obliged to clarify and fix some things:
I originally took the first Zip implementation verbatim from Bart De Smet's blog
Added enumerator disposing (which was also noted on Bart's original post)
Added null parameter checking (also discussed in Bart's post)
As a update to anyone stumbling across this question, .Net 4.0 supports this natively as ex from MS:
int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };
var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second);
Documentation:
The method merges each element of the first sequence with an element that has the same index in the second sequence. If the sequences do not have the same number of elements, the method merges sequences until it reaches the end of one of them. For example, if one sequence has three elements and the other one has four, the result sequence will have only three elements.
Think about what you're asking a bit more closely here:
You want to combine two IEnumerables in which "the indexes of the elements joined together in the KeyValuePair are the same", but you "don't have a count or an index for the items I'm merging".
There's no guarantee your IEnumerables are even sorted or unsorted. There's no correlation between your two IEnumerable objects, so how can you expect to correlate them?
Look at nextension:
Currently Implemented Methods
IEnumerable
ForEach Performs a specified action on each element of the IEnumerable.
Clump Groups items into same size lots.
Scan Creates a list by applying a delegate to pairs of items in the IEnumerable.
AtLeast Checks there are at least a certain amount of items in the IEnumerable.
AtMost Checks there are no more than a certain amount of items in the IEnumerable.
Zip Creates a list by combining two other lists into one.
Cycle Creates a list by repeating another list.
I would use something along the lines of -
IEnumerable<KeyValuePair<T,U>> Merge<T,U>(IEnumerable<T> keyCollection, IEnumerable<U> valueCollection)
{
var keys = keyCollection.GetEnumerator();
var values = valueCollection.GetEnumerator();
try
{
keys.Reset();
values.Reset();
while (keys.MoveNext() && values.MoveNext())
{
yield return new KeyValuePair<T,U>(keys.Current,values.Current);
}
}
finally
{
keys.Dispose();
values.Dispose();
}
}
This should work correctly, and cleanup properly afterwards.
Untested, but should work:
IEnumerable<KeyValuePair<T, U>> Zip<T, U>(IEnumerable<T> t, IEnumerable<U> u) {
IEnumerator<T> et = t.GetEnumerator();
IEnumerator<U> eu = u.GetEnumerator();
for (;;) {
bool bt = et.MoveNext();
bool bu = eu.MoveNext();
if (bt != bu)
throw new ArgumentException("Different number of elements in t and u");
if (!bt)
break;
yield return new KeyValuePair<T, U>(et.Current, eu.Current);
}
}
You could use the Zip methods in MoreLINQ.
The MSDN has the following Custom Sequence Operators example. And Welbog is right; if you have no index on the underlying data you have no guarantee that the operation does what you exspect.
Another implementation from the functional-dotnet project by Alexey Romanov:
/// <summary>
/// Takes two sequences and returns a sequence of corresponding pairs.
/// If one sequence is short, excess elements of the longer sequence are discarded.
/// </summary>
/// <typeparam name="T1">The type of the 1.</typeparam>
/// <typeparam name="T2">The type of the 2.</typeparam>
/// <param name="sequence1">The first sequence.</param>
/// <param name="sequence2">The second sequence.</param>
/// <returns></returns>
public static IEnumerable<Tuple<T1, T2>> Zip<T1, T2>(
this IEnumerable<T1> sequence1, IEnumerable<T2> sequence2) {
using (
IEnumerator<T1> enumerator1 = sequence1.GetEnumerator())
using (
IEnumerator<T2> enumerator2 = sequence2.GetEnumerator()) {
while (enumerator1.MoveNext() && enumerator2.MoveNext()) {
yield return
Pair.New(enumerator1.Current, enumerator2.Current);
}
}
//
//zip :: [a] -> [b] -> [(a,b)]
//zip (a:as) (b:bs) = (a,b) : zip as bs
//zip _ _ = []
}
Replace Pair.New with new KeyValuePair<T1, T2> (and the return type) and you're good to go.
JaredPar has a library with a lot of useful stuff in it, include Zip which will enable what you want to do.
I have a situation where I need a generic method to which I can pass two collections of type T along with a delegate that compares the two collections and returns true if every element in collection 1 has an equal element in collection 2, even if they are not in the same index of the collection. What I mean by "equal" is handled by the delegate. My initial thought was to return false if the collections were different lengths and otherwise sort them and then compare them like parallel arrays. Then it occurred to me that I can't sort a collection of a generic type without the types sharing an interface. So now I am thinking a LINQ expression might do the trick, but I can't think of how to write it. Consider my current code:
private static bool HasSameCollectionItems<T>(ICollection<T> left, ICollection<T> right, Func<T, T, bool> func)
{
if (left.Count != right.Count)
{
return false;
}
foreach (var item in left)
{
bool leftItemIsInRightCollection = ??? MAGIC ???
if (!leftItemIsInRightCollection)
{
return false;
}
}
return true;
}
I would like to replace ??? MAGIC ??? with a LINQ expression to see if item is "equal" to an element in right using the passed in delegate func. Is this even possible?
Note: For reasons I don't want to bother getting into here, impelemnting IEquatable or overriding the Equals method is not an option here.
It looks like you want .All() and .Any() methods (first method checks that all elements satisfy condition second only check if such an element exist) :
bool leftItemIsInRightCollection = right.Any(rItem => func(item, rItem));
Also i'd refactor your code to something like :
private static bool HasSameCollectionItems<T>(ICollection<T> left, ICollection<T> right, Func<T, T, bool> func)
{
return left.Count == right.Count && left.All(LI => right.Any(RI => func(LI, RI)));
}
The following works by checking whether there are element in left which are not in right.
If you insist on a delegate to determine equality, you can use the FuncEqualityComparer from here. (Note that you must also provide an implementation for Object.GetHashCode)
private static bool HasSameCollectionItems<T>(ICollection<T> left, ICollection<T> right, IEqualityComparer<T> comparer)
{
if (left.Count != right.Count) return false;
return !left.Except(right, comparer).Any();
}
I have a LINQ query that looks like this:
var p = option.GetType().GetProperties().Where(t => t.PropertyType == typeof(bool));
What is the most efficient way to get the items which aren't included in this query, without executing a second iteration over the list.
I could easily do this with a for loop but I was wondering if there's a shorthand with LINQ.
var p = option.GetType().GetProperties().ToLookup(t => t.PropertyType == typeof(bool));
var bools = p[true];
var notBools = p[false];
.ToLookup() is used to partition an IEnumerable based on a key function. In this case, it will return an Lookup which will have at most 2 items in it. Items in the Lookup can be accessed using a key similar to an IDictionary.
.ToLookup() is evaluated immediately and is an O(n) operation and accessing a partition in the resulting Lookup is an O(1) operation.
Lookup is very similar to a Dictionary and have similar generic parameters (a Key type and a Value type). However, where Dictionary maps a key to a single value, Lookup maps a key to an set of values. Lookup can be implemented as IDictionary<TKey, IEnumerable<TValue>>
.GroupBy() could also be used. But it is different from .ToLookup() in that GroupBy is lazy evaluated and could possibly be enumerated multiple times. .ToLookup() is evaluated immediately and the work is only done once.
You cannot get something that you don't ask for. So if you exlude all but bool you can't expect to get them later. You need to ask for them.
For what it's worth, if you need both, the one you want and all other in a single query you could GroupBy this condition or use ToLookup which i would prefer:
var isboolOrNotLookup = option.GetType().GetProperties()
.ToLookup(t => t.PropertyType == typeof(bool)); // use PropertyType instead
Now you can use this lookup for further processing. For example, if you want a collection of all properties which are bool:
List<System.Reflection.PropertyInfo> boolTypes = isboolOrNotLookup[true].ToList();
or just the count:
int boolCount = isboolOrNotLookup[true].Count();
So if you want to process all which are not bool:
foreach(System.Reflection.PropertyInfo prop in isboolOrNotLookup[false])
{
}
Well, you could go for source.Except(p), but it would reiterate the list and perform a lot of comparisons.
I'd say - write an extension method that does it using foreach, basically splitting the list into two destinations. Or something like this.
How about:
public class UnzipResult<T>{
private readonly IEnumearator<T> _enumerator;
private readonly Func<T, bool> _filter;
private readonly Queue<T> _nonMatching = new Queue<T>();
private readonly Queue<T> _matching = new Queue<T>();
public IEnumerable<T> Matching {get{
if(_matching.Count > 0)
yield return _matching.Dequeue();
else {
while(_enumerator.MoveNext()){
if(_filter(_enumerator.Current))
yield return _enumerator.Current;
else
_nonMatching.Enqueue(_enumerator.Current);
}
yield break;
}
}}
public IEnumerable<T> Rest {get{
if(_matching.Count > 0)
yield return _nonMatching.Dequeue();
else {
while(_enumerator.MoveNext()){
if(!_filter(_enumerator.Current))
yield return _enumerator.Current;
else
_matching.Enqueue(_enumerator.Current);
}
yield break;
}
}}
public UnzipResult(IEnumerable<T> source, Func<T, bool> filter){
_enumerator = source.GetEnumerator();
_filter = filter;
}
}
public static UnzipResult<T> Unzip(this IEnumerable<T> source, Func<T,bool> filter){
return new UnzipResult(source, filter);
}
It's written in notepad, so probably doesn't compile, but my idea is: whatever collection you enumerate (matching or non-matching), you only enumerate the source once. And it should work fairly well with those pesky infinite collections (think yield return random.Next()), unless all elements do/don't fulfil filter.
i want to check for the occurrence of some given items in the collection and thought it work like this but it doesn't
public static bool ContainsAny<T>(this IEnumerable<T> collection, IEnumerable<T> otherCollection)
{
if (otherCollection == null)
throw new ArgumentNullException("otherCollection", ExceptionResources.NullParameterUsed);
if (collection == null)
throw new ArgumentNullException("collection", ExceptionResources.ExtensionUsedOnNull);
else
return Enumerable.Any<T>(otherCollection, new Func<T, bool>(((Enumerable)collection).Contains<T>));
}
I want to get true if the specified collection contains any of the otherCollection items, otherwise false.
But there is an error telling me that i can not convert system.collections.generic.iEnumerable>T> in system.linq.Enumberable. Where is my mistake?
This should work:
return otherCollection.Any(collection.Contains);
You don't need any cast to call Contains method,because there is already an extension method that takes an IEnumerable<T> as first parameter.