I know when Linq's Any() extension is used to determine if an enumerable has at least one element it will only consume a single element. But how does that work actually? Does it have to cast all items in the enumerable first, or does it just cast them one at a time, starting with the first and stopping there?
Any() works on an IEnumerable<T> so no cast is required. It's implementation is very simple, it simply iterates through the enumerable and sees if it can find any elements matching the specified criteria.
Simple implementation looks like:
public bool Any<T>(IEnumerable<T> list)
{
using (var enumerator = list.GetEnumerator())
{
return enumerator.MoveNext();
}
}
So, no any casting required
Code in the public static class Enumerable:
public static bool Any<TSource>(this IEnumerable<TSource> source) {
if(source==null) {
throw Error.ArgumentNull("source");
}
using(IEnumerator<TSource> enumerator=source.GetEnumerator()) {
if(enumerator.MoveNext()) {
return true;
}
}
return false;
}
public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
if(source==null) {
throw Error.ArgumentNull("source");
}
if(predicate==null) {
throw Error.ArgumentNull("predicate");
}
foreach(TSource local in source) {
if(predicate(local)) {
return true;
}
}
return false;
}
Not seen the casting, but generic.
Related
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);
How can I integrate the .DefaultIfEmpty() extension method so I have not to use
.FirstOrDefault() ?? String.Empty;
Code:
(from role in roleList
let roleArray = role.RoleId.Split(new char[] { WorkflowConstants.WorkflowRoleDelimiter })
where roleArray.Length.Equals(_SplittedRoleIdArrayLength) &&
HasAccessToCurrentUnit(roleArray[_UnitIndexInRoleId])
select roleArray[_LevelIndexInRoleId]).FirstOrDefault() ?? String.Empty;
You could use:
var query = ...;
return query.DefaultIfEmpty(string.Empty).First();
But this doesn't reduce the complexity IMO.
If you're interested in extension method then you could use something like this:
public static class Helpers
{
public static string FirstOrEmpty(this IEnumerable<string> source)
{
return source.FirstOrDefault() ?? string.Empty;
}
}
Edit
This method isn't generic because then we'd have to use default(T) and it'll give us null instead of string.Empty.
I found this course on PluralSight interesting and I remembered it when I saw this question.
You could watch the whole course, but the Map Reduce and Option<T> strategies especially with DefaultIfEmpty seemed like it could be a good fit to your use case.
Tactical Design Patterns in .NET: Control Flow
by Zoran Horvat
https://app.pluralsight.com/library/courses/tactical-design-patterns-dot-net-control-flow/table-of-contents
The code:
var query=(
from role in roleList
let delimiter=WorkflowConstants.WorkflowRoleDelimiter
let roleArray=role.RoleId.Split(new char[] { delimiter })
where roleArray.Length.Equals(_SplittedRoleIdArrayLength)
where HasAccessToCurrentUnit(roleArray[_UnitIndexInRoleId])
select roleArray[_LevelIndexInRoleId]
).DefaultIfEmpty("").FirstOrDefault();
For the suspicion about the semantic meaning of DefaultIfEmpty and FirstOrDefault, following is the code decompiled from the library:
Code
public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source)
{
return source.DefaultIfEmpty<TSource>(default(TSource));
}
public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source, TSource defaultValue)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return DefaultIfEmptyIterator<TSource>(source, defaultValue);
}
public static TSource First<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
if (list.Count > 0)
{
return list[0];
}
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
return enumerator.Current;
}
}
}
throw Error.NoElements();
}
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
if (list.Count > 0)
{
return list[0];
}
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
return enumerator.Current;
}
}
}
return default(TSource);
}
And here are something to mention:
DefaultIfEmpty has a parameterless overload, which invokes the parameterized overload with default(TSource) and return its result.
The only difference between parameterless FirstOrDefault and First, is the latter would throw when the collection is empty.
For more information, see Enumerable.FirstOrDefault<TSource> Method on MSDN.
FirstOrDefault semantically expressed first or default, and so called; it's not named first or null. In c#, default(T) for a reference type is null, but for non-reference type, it's not. For example, default(int) is zero.
The keyword default was never said null semantically. It's DEFAULT.
Also, for more information, default Keyword on MSDN.
.NET 6 introduces the concept of being able to pass in what the default value should be, should the item not be found. So for example, this code is now valid in .NET 6:
source.FirstOrDefault(String.Empty);
Or:
List<int> numbers = new List<int>();
var custom = numbers.FirstOrDefault(-1);
In the example above we don't need to be reliant on getting back 0
which is the default for int anymore. This could be handy when 0 is a
valid number in the context of using the list of numbers where as -1
isn't.
You can read more:
https://dotnetcoretutorials.com/2021/09/02/linq-ordefault-enhancements-in-net-6/
https://adamstorr.azurewebsites.net/blog/default-your-firstordefault-in-net6.0
Please, suggest the shortest way to convert Dictionary<Key, Value> to Hashset<Value>
Is there built-in ToHashset() LINQ extension for IEnumerables ?
Thank you in advance!
var yourSet = new HashSet<TValue>(yourDictionary.Values);
Or, if you prefer, you could knock up your own simple extension method to handle the type inferencing. Then you won't need to explicitly specify the T of the HashSet<T>:
var yourSet = yourDictionary.Values.ToHashSet();
// ...
public static class EnumerableExtensions
{
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source)
{
return source.ToHashSet<T>(null);
}
public static HashSet<T> ToHashSet<T>(
this IEnumerable<T> source, IEqualityComparer<T> comparer)
{
if (source == null) throw new ArgumentNullException("source");
return new HashSet<T>(source, comparer);
}
}
new HashSet<Value>(YourDict.Values);
What is Linq actually doing?
(I'm assuming this is for LINQ to Objects. Anything else will be implemented differently :)
It's just returning everything from the first, and then everything from the second. All data is streamed. Something like this:
public static IEnumerable<T> Concat(this IEnumerable<T> source1,
IEnumerable<T> source2)
{
if (source1 == null)
{
throw new ArgumentNullException("source1");
}
if (source2 == null)
{
throw new ArgumentNullException("source1");
}
return ConcatImpl(source1, source2);
}
private static IEnumerable<T> ConcatImpl(this IEnumerable<T> source1,
IEnumerable<T> source2)
{
foreach (T item in source1)
{
yield return item;
}
foreach (T item in source2)
{
yield return item;
}
}
I've split this into two methods so that the argument validation can be performed eagerly but I can still use an iterator block. (No code within an iterator block is executed until the first call to MoveNext() on the result.)
It enumerates each collection in turn, and yields each element. Something like that :
public static IEnumerable<T> Concat<T>(this IEnumerable<T> source, IEnumerable<T> other)
{
foreach(var item in source) yield return item;
foreach(var item in other) yield return item;
}
(if you look at the actual implementation using Reflector, you will see that the iterator is actually implemented in a separate method)
It depends on the LINQ provider you are using. LinqToSql or L2E might use a database UNION, whereas LINQ to Objects might just enumerate both collections for your in turn.
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;
}