Use .DefaultIfEmpty() instead of .FirstOrDefault() ?? String.Empty; - c#

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

Related

Generic Method to get Distinct of LIST<T>

I am trying to compare (values of the properties) a instance of type in a List and eliminate duplicates.
According to MSDN GetHashCode() is one of the way to compare two objects.
A hash code is intended for efficient insertion and lookup in
collections that are based on a hash table. A hash code is not a
permanent value
Considering that, I started writing my extension method as bellow
public static class Linq
{
public static IEnumerable<T> DistinctObjects<T>(this IEnumerable<T> source)
{
List<T> newList = new List<T>();
foreach (var item in source)
{
if(newList.All(x => x.GetHashCode() != item.GetHashCode()))
newList.Add(item);
}
return newList;
}
}
This condition always gives me false though the data of the object is same.
newList.All(x => x.GetHashCode() != item.GetHashCode())
Finally I would like to use it like
MyDuplicateList.DistinctObjects().ToList();
If comparing all fields of the object is too much, I am okay to use it like,
MyDuplicateList.DistinctObjects(x=>x.Id, x.Name).ToList();
Here I am telling compare only these two fields of those objects.
After reading your comments I would propose this solution:
public static IEnumerable<TSource> DistinctBy<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
HashSet<TResult> set = new HashSet<TResult>();
foreach(var item in source)
{
var selectedValue = selector(item);
if (set.Add(selectedValue))
yield return item;
}
}
Then you can use it like this:
var distinctedList = myList.DistinctBy(x => x.A);
or for multiple properties like that:
var distinctedList = myList.DistinctBy(x => new {x.A,x.B});
The advantage of this solution is you can exactly specify what properties should be used in distinction and you don't have to override Equals and GetHashCode for every object. You need to make sure that your properties can be compared.
You shouldn't need to create your own custom, generic method for this. Instead, provide a custom EqualityComparar for your data type:
var myDuplicates = myList.Distinct(new MyComparer());
Where you define a custom Comparer like this:
public class MyComparer : IEqualityComparer<Mine>
{
public bool Equals(Mine x, Mine y)
{
if (x == null && y == null) return true;
if (x == null || y == null) return false;
return x.Name == y.Name && x.Id == y.Id;
}
public int GetHashCode(Mine obj)
{
return obj.Name.GetHashCode() ^ obj.Id.GetHashCode();
}
}
Edit: I initially had incorrect code here, this should do what you want without you having to override an Equals operator

Does LinQ Any() cast all items in a collection?

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.

Can I use extension methods and LINQ in .NET 2.0 or 3.0?

When I try to add an extension method using the .NET 2.0 or 3.0 runtime, I get the error:
Cannot define a new extension method because the compiler required
type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be
found. Are you missing a reference to System.Core.dll?
But I can't find System.Core in the list of available references when I try to add it to the project. What do I need to do to be able to use extension methods and in turn LINQ on in my projects?
Extension methods were not added to .NET until 3.5. However, it was not a change to the CLR, but a change to the compiler that added them, so you can still use them in your 2.0 and 3.0 projects! The only requirement is you must have a compiler that can create 3.5 projects to be able to do this workaround (Visual Studio 2008 and above).
The error you get when you attempt to use an extension method is misleading as you do not truly need System.Core.dll to use extension methods. When you use a extension method, behind the scenes, the compiler is adding the [Extension] attribute to the function. If you have a compiler that understands what to do with the [Extension] attribute you can use it in your 2.0 and 3.0 projects if you create the attribute yourself.
Just add the following class to your project and you can then start using extension methods:
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class ExtensionAttribute : Attribute
{
}
}
The above code block is sitting inside System.Core.Dll, so that is why the error says you need to include the DLL file to use them.
Now if you want LINQ functionality that will take a little extra work. You will need to re-implement the extension methods yourself. To mimic the full LINQ to SQL functionality the code can get quite complicated. However, if you are just using LINQ to Objects most LINQ methods are not complicated to implement. Here are a few LINQ to Objects replacement functions from a project I wrote out to get you started.
public static class LinqReplacement
{
public delegate TResult Func<T, TResult>(T arg);
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null)
throw new ArgumentNullException("source");
if (predicate == null)
throw new ArgumentNullException("predicate");
foreach (TSource item in source)
{
if (predicate(item) == true)
return item;
}
throw new InvalidOperationException("No item satisfied the predicate or the source collection was empty.");
}
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
throw new ArgumentNullException("source");
foreach (TSource item in source)
{
return item;
}
return default(TSource);
}
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
{
foreach (object item in source)
{
yield return (TResult)item;
}
}
public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
{
if (source == null)
throw new ArgumentNullException("source");
if (selector == null)
throw new ArgumentNullException("selector");
foreach (TSource item in source)
{
foreach (TResult subItem in selector(item))
{
yield return subItem;
}
}
}
public static int Count<TSource>(this IEnumerable<TSource> source)
{
var asCollection = source as ICollection;
if(asCollection != null)
{
return asCollection.Count;
}
int count = 0;
foreach (TSource item in source)
{
checked //If we are counting a larger than int.MaxValue enumerable this will cause a OverflowException to happen when the counter wraps around.
{
count++;
}
}
return count;
}
}
A library with the full re-implemenation of LINQ to Objects with the ExtensionAttribute already added in can be found in the LinqBridge project (Thanks Allon Guralnek).

Does calling .Last() on an IList iterate the entire list? [duplicate]

This question already has answers here:
What is the performance of the Last() extension method for List<T>?
(5 answers)
Closed 7 years ago.
Does the .Last() extension method take into account if it's called on an IList? I'm just wondering if there's a significant performance difference between these:
IList<int> numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int lastNumber1 = numbers.Last();
int lastNumber2 = numbers[numbers.Count-1];
Intuition tells me that the first alternative is O(n) but the second is O(1). Is .Last() "smart" enough to try casting it to an IList?
Probably not, as it can do list[list.count-1]
Verified by reflector:
public static TSource Last<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
int count = list.Count;
if (count > 0)
{
return list[count - 1];
}
}
...
}
This is an undocumented optimization, but the predicate-less overload of Enumerable.Last does indeed skip straight to the end.
Note that the overload with a predicate doesn't just go from the end, working backwards as you might expect - it goes forwards from the start. I believe this is to avoid inconsistency when the predicate may throw an exception (or cause other side effects).
See my blog post about implementing First/Last/Single etc for more information - and an inconsistency which is present between the overloads of Single/SingleOrDefault.
Reflector:
public static TSource Last<TSource>(this IEnumerable<TSource> source)
{
...
if (list != null)
{
int count = list.Count;
if (count > 0)
{
return list[count - 1];
}
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
...
}
}
throw Error.NoElements();
}
Answer: Yes.
Here's a neat way to find out:
class MyList<T> : IList<T> {
private readonly List<T> list = new List<T>();
public T this[int index] {
get {
Console.WriteLine("Inside indexer!");
return list[index];
}
set {
list[index] = value;
}
}
public void Add(T item) {
this.list.Add(item);
}
public int Count {
get {
Console.WriteLine("Inside Count!");
return this.list.Count;
}
}
// all other IList<T> interface members throw NotImplementedException
}
Then:
MyList<int> list = new MyList<int>();
list.Add(1);
list.Add(2);
Console.WriteLine(list.Last());
Output:
Inside Count!
Inside indexer!
2
If you try this:
Console.WriteLine(list.Last(n => n % 2 == 0));
then you get an exception in GetEnumerator showing that it is trying to walk the list. If we implement GetEnumerator via
public IEnumerator<T> GetEnumerator() {
Console.WriteLine("Inside GetEnumerator");
return this.list.GetEnumerator();
}
and try again we see
Inside GetEnumerator!
2
on the console showing that the indexer was never used.
Original poster is talking about an interface, not the implementation.
So it depends on the the underlying implementation behind the IList/Ilist<T> in question. You don't how how its indexer is implemented. I believe the framework's List<T> has a concrete implementation that utilizes an array, so a direct lookup is possible, but if all you have is an reference to IList<T>, that is not a given by any means.

A different take on FirstOrDefault

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;
}

Categories