Is there a dumb "all" in linq that evaluate all element? - c#

Just like operator "&" will execute second condition even if first one is false,
I'm looking for the same thing for "All". I want the result of "All" but also want each elements to be evaluated. I called that a dumbAll in my example.
Here is an example of why I want this.
main
{
Object[] array = InitSomeArray();
AreObjectValid = array.dumbAll(o => Validate(o));
//other stuff with AreObjectValid
}
private bool Validate(object o)
{
bool IsValid = IsPositiveNumeric(o.ToString());
HighLighInvalidObjectWhenInvalid(o, IsInvalid: !IsValid);
return IsValid;
}
Does such thing exists in linq?
Note : I already know how to handle this without link.

You can use other query operators to achieve the same. One example is to count how many objects satisfy the condition.
Object[] array = InitSomeArray();
var count = array.Count(o => Validate(o));
var areObjectsValid = count == array.Length;

Not really, but you can achieve this aggregating the results.
var allValid = array.Aggregate(true, (acc, o) => acc & Validate(o));

I like this less than the Aggregate answer (and the Count answer as long as you have an array), but here:
AreObjectValid = array.Select(o => Validate(o)).ToArray().All(b => b);
or, as Asad points out,
AreObjectValid = array.Select(Validate).ToArray().All(b => b);

There's a bunch of LINQ answers here, but because I believe LINQ transformations should ideally be side effect free, here's an approach that uses a foreach and doesn't really sacrifice too much conciseness.
bool all = true;
foreach(var o in array)
all &= Validate(o);
This evaluates Validate for each value, and at the end all will be false if any of the values failed validation.

Related

C# linq - Order by alphabetical, then by certain value [duplicate]

Can anyone explain what the difference is between:
tmp = invoices.InvoiceCollection
.OrderBy(sort1 => sort1.InvoiceOwner.LastName)
.OrderBy(sort2 => sort2.InvoiceOwner.FirstName)
.OrderBy(sort3 => sort3.InvoiceID);
and
tmp = invoices.InvoiceCollection
.OrderBy(sort1 => sort1.InvoiceOwner.LastName)
.ThenBy(sort2 => sort2.InvoiceOwner.FirstName)
.ThenBy(sort3 => sort3.InvoiceID);
Which is the correct approach if I wish to order by 3 items of data?
You should definitely use ThenBy rather than multiple OrderBy calls.
I would suggest this:
tmp = invoices.InvoiceCollection
.OrderBy(o => o.InvoiceOwner.LastName)
.ThenBy(o => o.InvoiceOwner.FirstName)
.ThenBy(o => o.InvoiceID);
Note how you can use the same name each time. This is also equivalent to:
tmp = from o in invoices.InvoiceCollection
orderby o.InvoiceOwner.LastName,
o.InvoiceOwner.FirstName,
o.InvoiceID
select o;
If you call OrderBy multiple times, it will effectively reorder the sequence completely three times... so the final call will effectively be the dominant one. You can (in LINQ to Objects) write
foo.OrderBy(x).OrderBy(y).OrderBy(z)
which would be equivalent to
foo.OrderBy(z).ThenBy(y).ThenBy(x)
as the sort order is stable, but you absolutely shouldn't:
It's hard to read
It doesn't perform well (because it reorders the whole sequence)
It may well not work in other providers (e.g. LINQ to SQL)
It's basically not how OrderBy was designed to be used.
The point of OrderBy is to provide the "most important" ordering projection; then use ThenBy (repeatedly) to specify secondary, tertiary etc ordering projections.
Effectively, think of it this way: OrderBy(...).ThenBy(...).ThenBy(...) allows you to build a single composite comparison for any two objects, and then sort the sequence once using that composite comparison. That's almost certainly what you want.
I found this distinction annoying in trying to build queries in a generic manner, so I made a little helper to produce OrderBy/ThenBy in the proper order, for as many sorts as you like.
public class EFSortHelper
{
public static EFSortHelper<TModel> Create<TModel>(IQueryable<T> query)
{
return new EFSortHelper<TModel>(query);
}
}
public class EFSortHelper<TModel> : EFSortHelper
{
protected IQueryable<TModel> unsorted;
protected IOrderedQueryable<TModel> sorted;
public EFSortHelper(IQueryable<TModel> unsorted)
{
this.unsorted = unsorted;
}
public void SortBy<TCol>(Expression<Func<TModel, TCol>> sort, bool isDesc = false)
{
if (sorted == null)
{
sorted = isDesc ? unsorted.OrderByDescending(sort) : unsorted.OrderBy(sort);
unsorted = null;
}
else
{
sorted = isDesc ? sorted.ThenByDescending(sort) : sorted.ThenBy(sort)
}
}
public IOrderedQueryable<TModel> Sorted
{
get
{
return sorted;
}
}
}
There are a lot of ways you might use this depending on your use case, but if you were for example passed a list of sort columns and directions as strings and bools, you could loop over them and use them in a switch like:
var query = db.People.AsNoTracking();
var sortHelper = EFSortHelper.Create(query);
foreach(var sort in sorts)
{
switch(sort.ColumnName)
{
case "Id":
sortHelper.SortBy(p => p.Id, sort.IsDesc);
break;
case "Name":
sortHelper.SortBy(p => p.Name, sort.IsDesc);
break;
// etc
}
}
var sortedQuery = sortHelper.Sorted;
The result in sortedQuery is sorted in the desired order, instead of resorting over and over as the other answer here cautions.
if you want to sort more than one field then go for ThenBy:
like this
list.OrderBy(personLast => person.LastName)
.ThenBy(personFirst => person.FirstName)
Yes, you should never use multiple OrderBy if you are playing with multiple keys.
ThenBy is safer bet since it will perform after OrderBy.

Optimize Linq in C#

I have columns list in which I need to assign Isselected as true for all except for two columns. (Bug and feature). I have used this following code to achieve it and working fine, but is there any quick or easy way to achieve the same?
DisplayColumns.ToList().ForEach(a => a.IsSelected = true);
DisplayColumns.ToList().Where(a => a.ColumnName == "Bug" || a.ColumnName == "Feature").ToList().ForEach(a => a.IsSelected = false);
Thanks in advance
I have used this following code to achieve it and working fine, but is there any quick or easy way to achieve the same?
Well there's a cleaner way to achieve it in my view - just don't use lambdas etc at all:
foreach (var item in DisplayColumns)
{
item.IsSelected = item.ColumnName != "Bug" && item.ColumnName != "Feature";
}
You can make the decision in one go - it's false if the column name is either "bug" or "feature"; it's true otherwise. And you don't need to call ToList and use ForEach when the C# language has a perfectly good foreach loop construct for when you want to execute some code using each item in a collection.
I love LINQ - it's fantastic - but its sweet spot is querying (hence the Q) rather than manipulation. In this case only the ToList part is even part of LINQ - List<T>.ForEach was introduced in .NET 2.0, before LINQ.
Sure, you can assign the IsSelected at once.
DisplayColumns.ToList().ForEach(a => a.IsSelected = !(a.ColumnName == "Bug" || a.ColumnName == "Feature"));
Provided that DisplayColumns isn't a projection of an anonymous type (in which case the properties are not re-assignable), you'll be able to change the flag in a single pass iteration through the collection.
You can also use Contains to ease the comparison. At class scope:
private static readonly string[] _searches = new [] {"Bug", "Feature"}
In your method:
DisplayColumns
.ToList() // For List.ForEach, although not #JonSkeet's caveat re mutating in Linq
.ForEach(a => a.IsSelected = !_searches.Contains(a.ColumnName));
Edit
As others have mentioned, creation of a new list simply to gain access to .ForEach to change objects in the (original) collection is wasteful and changes will be lost on a collection of value types. Rather, iterate over the original collection with foreach (or even for).
Firstly you only need to call ToList() once when creating a collection from your IEnumerable.
doing this after each operator is costly and redundant.
Secondly just change your condition . all true except for the tow.
DisplayColumns.Where(a => a.ColumnName != "Bug" && a.ColumnName != "Feature").ForEach(a => a.IsSelected = true).ToList();
Edit :
I'm sorry i like a part john's answer since this can be a re occurring thing , or IsSelected could be a Nullable , any ways lets keep it as general as possible .
I also like Stuart's approach , with the collection ( i also thought of it but didn't want to confuse . so let's give the best of all worlds.
when using linq we are actually building an expression tree at the end of which we can choose to materialize into a collection.
there for _searchs can change and each time we materialize that expression we do it with the values currently in that collection , thous making our code much more general .
private static readonly string[] _searches = new [] {"Bug", "Feature"}
DisplayColumns.ForEach(a => a.IsSelected = !_searchs.Contains(a.ColumnName)).ToList();
I'm assuming ForEach is an Extension method for type IEnumrable
Maybe this:
tmp = DisplayColumns.ToList();
var res = tmp.Except(tmp.Where(a => a.ColumnName == "Bug" || a.ColumnName == "Feature"));
foreach(var x in res) x.IsSeleceted = true;
Without using foreach
DisplayColumns
.Select(s=> {
s.IsSelected = (s.ColumnName == "Bug" && s.ColumnName == "Feature");
return s;
});

Determine if an int value exists once in an array

I know you can use Any, Exists, and Single with LINQ but can't quite get this to work. I need to do a lookup based on an id to see if it's in the array and make sure that there is only ONE match on that value. because if there are 2 it's gonna cause an issue..the requirement that I'm checking is that the array only has one and only one of each ID in the array.
Here's what I tried
if(someIntArray.Single(item => item = 3)
//... we found the value 8 in the array only once so now we can be confident and do something
Here's how I would solve this:
if (someIntArray.Count(item => item == 3) == 1)
{
//only one '3' found in the array
...
}
I created a One() extension method set for just this situation:
public static bool One<T>(this IEnumerable<T> sequence)
{
var enumerator = sequence.GetEnumerator();
return enumerator.MoveNext() && !enumerator.MoveNext();
}
public static bool One<T>(this IEnumerable<T> sequence, Func<T, bool> predicate)
{
return sequence.Where(predicate).One();
}
//usage
if (someIntArray.One(item => item == 3)) ...
The problem with Single() is that it throws an exception if there isn't exactly one element. You can wrap it in a try-catch, but these are cleaner, and more efficient than Count() in most cases where there's more than one matching element. Unfortunately, there's no way around having to check the entire array to verify that there are either no elements or only one that matches a predicate, but this will at least "fail fast" if there are two or more, where Count() will always evaluate the entire Enumerable whether there's one matching element or fifty.
I think you're overthinking this.
var targetNumber = 3;
var hasExactlyOne = someIntArray.Count(i => i == targetNumber) == 1;
Using LINQ expression:
var duplicates = from i in new int[] { 2,3,4,4,5,5 }
group i by i into g
where g.Count() > 1
select g.Key
Results:
{4,5}
And of course you could check duplicates.Count() > 0 or log the ones that are a problem or whatever you need to do.
got it working:
if(someIntArray.Single(item => item = 3) > 0)
doh

Find Max/Min element without using IComparable<T>

Say I have the following:
public Class BooClass
{
public int field1;
public double field2;
public DateTime field3;
}
public List<BooClass> booList;
So for example how do I get the element with the earliest time in field3 using booList.Find()
Edit Apologies, I meant to make all the fields public for simplicity of the example. I know can do it in linq, I wondered if there is a simple single line condition for the Find method.
F# has handy minBy and maxBy operators, which I like to implement as C# extension methods, since the Linq library omits them. It's a bit of work, but only a bit, and it allows you to avoid complex expressions such as
var earliest = booList.First(b => b.Field3 == booList.Min(e => e.Field3));
Instead, you can type this:
var earliest = booList.MinBy(b => b.Field3);
A simple implementation:
static T MinBy<T, C>(this IEnumerable<T> sequence, Func<T, C> keySelector)
{
bool first = true;
T result = default(T);
C minKey = default(C);
IComparer<C> comparer = Comparer<C>.Default; //or you can pass this in as a parameter
foreach (var item in sequence)
{
if (first)
{
result = item;
minKey = keySelector.Invoke(item);
first = false;
continue;
}
C key = keySelector.Invoke(item);
if (comparer.Compare(key, minKey) < 0)
{
result = item;
minKey = key;
}
}
return result;
}
This is also somewhat more efficient than the complex expression at the top, since MinBy iterates the sequence exactly once, while the expression iterates more than once and less than or equal to twice. And, of course, sorting and then taking the first item requires sorting, which is O(n log n), while this is just O(n).
As noted by Saeed Amiri, this approach doesn't work if you are relying on Linq to SQL or any other IQueryable<> provider. (More precisely, it works inefficiently because it pulls the objects from the database and works on them locally.) For a solution that doesn't do this, see Saeed's answer.
You could also make an extension method based on that approach, but as I am on my phone at the moment I'll leave the implementation as the proverbial "exercise for the reader."
You'll need to expose field3 through through a public property (we'll call it Field3), but you could use this:
var earliest = booList.First(b => b.Field3 == booList.Min(e => e.Field3));
Take a look at Enumerable.First and Enumerable.Min
NOTE: That this has a time complexity of O(n^2) (quadratic time) because it is traversing the list via Min each iteration. A large enough collection will see serious performance issues compared to Saeed Amiri's answer, which runs in O(n) (linear time).
Use OrderBy Then get the first element
var result = booList.OrderBy(p => p.field3).FirstOrDefault();
The O(n) approach is as follows. First find min date (for field3), then find first object with this min date:
var minDate = booList.Min(x=>x.field3);
var item = booList.First(x=>x.field3 == minDate);
Just make your property public.
As far as I can tell, there is no way to retrieve the BooClass object with the minimal date by just using List<T>.Find. Of course you can do this:
void Main()
{
List<BooClass> booList = new List<BooClass> {
new BooClass { field3 = DateTime.MaxValue},
new BooClass { field3 = DateTime.Now },
new BooClass { field3 = DateTime.MinValue }};
var pred = GetPredicate(booList);
var result = booList.Find(pred);
}
public Predicate<BooClass> GetPredicate(List<BooClass> boos)
{
var minDate = boos.Min(boo => boo.field3);
return bc => bc.field3 == minDate;
}
(which - just like Saeed's solution - also has O(n) time complexity), but I guess that would be considered cheating...
If you don't want to define a MinBy method, you can use aggregate like so:
booList.Aggregate((currMin, test) => currMin < test ? currMin : test);
To support empty lists, seed the aggregate with null, like so:
booList.Aggregate(null, (currMin, test) => null == currMin || currMin > test ? test : currMin);
This solution is O(n)

LINQ query to return whether an item is found in an array?

I am learning LINQ, and I am not sure how to write a query to return a boolean indicating whether an item is found in an array. I have a very simple list:
var targetProperties = new string[] { "SelectedDate", "SelectedMonth" };
I need to write a LINQ query that will return true if an item passed in is in the array, and false if it isn't. What would that query look like?
bool answer = targetProperties.Any(x => x == "SelectedDate");
targetProperties.Contains("SelectedDate") ?

Categories