How do you sort array of arrays in c#? - c#

I'm trying to sort a list of intervals based on start time (which is the first element).
public static int[][] SortIntervals(int[][] intervals)
{
intervals.Sort(Comparer<int[]>.Create((a, b) => a[0].CompareTo(b[0]))); // error
return intervals;
}
Error -CS1503 Argument 1: cannot convert from 'System.Collections.Generic.Comparer<int[]>' to 'System.Array'
I can sort a list of intervals just fine, maybe I'm missing the correct syntax for it.
public static List<int[]> SortIntervals(List<int[]> intervals)
{
intervals.Sort(Comparer<int[]>.Create((a, b) => a[0].CompareTo(b[0])));
return intervals;
}

You are right, in case of array you should use different syntax Array.Sort:
public static int[][] SortIntervals(int[][] intervals)
{
if (null == intervals)
throw new ArgumentNullException(nameof(intervals));
Array.Sort(intervals, (a, b) => a[0].CompareTo(b[0]));
return intervals;
}

Related

Creating variables from an array in C# [duplicate]

In JavaScript ES6, you are able to destructure arrays like this:
const [a,b,...rest] = someArray;
where a is the first element in the array, b is the second, and rest is an array with the remaining elements.
I know in C#7 that you can destructure tuples during assignment, but could not find anything related to destructuring arrays/enumerables like this:
var (a,b) = someTuple;
I have an IEnumerable where I need the first and second elements as variables, and I need the rest of the elements as another IEnumerable. I have a solution, but feel that destructuring will look cleaner.
It turns out not only tuples can be deconstructed but any type which has Deconstruct static (or extension) method with matching signature. Doing deconstruction correctly for IEnumerable is not trivial (see library suggested by David Arno in this answer), so let's see how it works with simple IList instead (implementation is irrelevant, this one is for example and of course can be better/different):
public static class Extensions {
public static void Deconstruct<T>(this IList<T> list, out T first, out IList<T> rest) {
first = list.Count > 0 ? list[0] : default(T); // or throw
rest = list.Skip(1).ToList();
}
public static void Deconstruct<T>(this IList<T> list, out T first, out T second, out IList<T> rest) {
first = list.Count > 0 ? list[0] : default(T); // or throw
second = list.Count > 1 ? list[1] : default(T); // or throw
rest = list.Skip(2).ToList();
}
}
Then (after adding relevant using statements if necessary) you can use exactly the syntax you want:
var list = new [] {1,2,3,4};
var (a,rest) = list;
var (b,c,rest2) = list;
Or you can chain deconstruction like this (because last returned value can itself be deconstructed):
var (a, (b, (c, rest))) = list;
With last version, you can deconstruct to any number of items using single Deconstruct method (that one which returns first item and the rest).
For real usage for IEnumerables, I'd suggest to not reimplement the wheel and use David Arno's library mentioned in this answer.
If you want a solution that is fully integrated with the C# language features, use Evk's answer, which hides some of the implementation detail. If you don't care about that, you can use either of the answers.
To my knowledge there is not. However, it is not very hard to make something similar.
What about an extension method like this:
public static class EX
{
public static void Deconstruct<T>(this T[] items, out T t0)
{
t0 = items.Length > 0 ? items[0] : default(T);
}
public static void Deconstruct<T>(this T[] items, out T t0, out T t1)
{
t0 = items.Length > 0 ? items[0] : default(T);
t1 = items.Length > 1 ? items[1] : default(T);
}
}
And you can use it like so:
int[] items = { 1, 2 };
items.Deconstruct(out int t0);
The drawback is that you need an extension method per number of items to return. So if you have more than a few variables to return, this method might not be very useful.
Note that I left out checking the length, and related stuff, but you understand what needs to be done I guess.
What you are describing is generally known in functional languages as "cons", which often takes the form:
let head :: tail = someCollection
I did propose this be added to C#, but it didn't receive very favourable feedback. So I wrote my own, which you can use via the Succinc<T> nuget package.
It uses deconstruction to achieve that splitting of the head and tail of any IEnumerable<T>. Deconstructs can be nested, so you can use it to extract multiple elements in one go:
var (a, (b, rest)) = someArray;
This potentially could provide the functionality you are after.
To extend the solutions hinted by other contributors, I provide an answer that uses IEnumerable. It might not be optimized but it works quite well.
public static class IEnumerableExt
{
public static void Deconstruct<T>(this IEnumerable<T> seq, out T first, out IEnumerable<T> rest)
{
first = seq.FirstOrDefault();
rest = seq.Skip(1);
}
public static void Deconstruct<T>(this IEnumerable<T> seq, out T first, out T second, out IEnumerable<T> rest)
=> (first, (second, rest)) = seq;
public static void Deconstruct<T>(this IEnumerable<T> seq, out T first, out T second, out T third, out IEnumerable<T> rest)
=> (first, second, (third, rest)) = seq;
public static void Deconstruct<T>(this IEnumerable<T> seq, out T first, out T second, out T third, out T fourth, out IEnumerable<T> rest)
=> (first, second, third, (fourth, rest)) = seq;
public static void Deconstruct<T>(this IEnumerable<T> seq, out T first, out T second, out T third, out T fourth, out T fifth, out IEnumerable<T> rest)
=> (first, second, third, fourth, (fifth, rest)) = seq;
}
Then just use these deconstructors like this:
var list = new[] { 1, 2, 3, 4 };
var (a, b, rest1) = list;
var (c, d, e, f, rest2) = rest1;
Console.WriteLine($"{a} {b} {c} {d} {e} {f} {rest2.Any()}");
// Output: 1 2 3 4 0 0 False
Really quick: No.
C# does not support destructuring for Arrays yet.
Currently, I cannot find any information of this on the roadmap, either. Seems like there will be a lot of waiting involved until we get this syntactic sugar by default.
As #Nekeniehl added in the comments, it can be implemented though: gist.github.com/waf/280152ab42aa92a85b79d6dbc812e68a
In C# you will need to write your own, like this one I'm using:
public static class ArrayExtensions
{
public static void Deconstruct<T>(this T[] array, out T first, out T[] rest)
{
first = array.Length > 0 ? array[0] : default(T);
rest = array.Skip(1).ToArray();
}
public static void Deconstruct<T>(this T[] array, out T first, out T second, out T[] rest)
=> (first, (second, rest)) = array;
public static void Deconstruct<T>(this T[] array, out T first, out T second, out T third, out T[] rest)
=> (first, second, (third, rest)) = array;
public static void Deconstruct<T>(this T[] array, out T first, out T second, out T third, out T fourth, out T[] rest)
=> (first, second, third, (fourth, rest)) = array;
public static void Deconstruct<T>(this T[] array, out T first, out T second, out T third, out T fourth, out T fifth, out T[] rest)
=> (first, second, third, fourth, (fifth, rest)) = array;
// .. etc.
}
Then simply do:
var (first, second,_ , rest) = new[] { 1, 2, 3, 4 }
There is no special syntax for it in the language.
You could leverage the tuple syntax, though, to arrive at this
class Program
{
static void Main(string[] args)
{
int[] ints = new[] { 1, 2, 3 };
var (first, second, rest) = ints.Destruct2();
}
}
public static class Extensions
{
public static (T first, T[] rest) Desctruct1<T>(this T[] items)
{
return (items[0], items.Skip(1).ToArray());
}
public static (T first, T second, T[] rest) Destruct2<T>(this T[] items)
{
return (items[0], items[1], items.Skip(2).ToArray());
}
}
(which should be extended with error handling for obvious error scenarios before being used in production code).
You need to be slightly careful if you want to handle infinite streams, as from a while(true) yield return block for example. In that case, you can't practically check the length of the stream to make sure you have enough items to populate the requested tuple.
If your source is actually infinite a combination of the above approaches would work -- rather than counting the length of the IEnumerable<T>, just check that it has any content at all, and then implement the multi-parameter overloads in terms of the single-parameter overload:
public static void Deconstruct<T>(this IEnumerable<T> list, out T head, out IEnumerable<T> tail)
{
head = list.First(); // throws InvalidOperationException for empty list
tail = list.Skip(1);
}
public static void Deconstruct<T>(this IEnumerable<T> list, out T head, out T next, out IEnumerable<T> tail)
{
head = list.First();
(next, tail) = list.Skip(1);
}
The critical question is what you want to happen when the stream runs out. The code above will throw an InvalidOperationException. Returning default<T> might not be what you want instead. In a functional context you'd typically be doing a cons, and splitting the stream into a single head an stream tail - and then checking for empty streams outside of your cons implementation (so outside of the Deconstruct method).
I tried to make it more shorter and performance effective. So I avoided the calling of IEnumerable<T>.ToList() method, which would be expensive if we had a large list.
public static void Deconstruct<T>(this IEnumerable<T> list, out T first, out IEnumerable<T> rest) {
first = list.FirstOrDefault();
rest = list.Skip(1);
}
public static void Deconstruct<T>(this IEnumerable<T> list, out T first, out T second, out IEnumerable<T> rest) {
first = list.FirstOrDefault();
(second, rest) = list.Skip(1);
}
public static void Deconstruct<T>(this IEnumerable<T> list, out T first, out T second, out T third, out IEnumerable<T> rest) {
first = list.FirstOrDefault();
(second, third, rest) = list.Skip(1);
}
We have it in C# 11 now as part of list patterns.
Usage examples:
List<int> list = new() { 1, 2, 3 };
// Here array must contain exactly 3 elements to match
// taking first element, disregarding last 2 ("_" disregards a single element)
if (list is [var firstElm, _, _])
{
// Do stuff with firstElm
}
// Do stuff with firstElm here too
Or
public void SomeFunc(int[] arr)
{
// guard
if (arr is not [var a, var b, var c]) return;
// act
a = b - c;
}
Or
Queue<int[]> queue = new ();
queue.Enqueue(new int[] { 1, 2, 3 });
// Here matching an array with length >= 2
// and taking first 2 elements (".." matches and disregards 0 or more elements)
// Arrays with less then 2 elements won't match
while (queue.TryDequeue(out var arr) && arr is [var a, var b, ..])
{
// Do stuff with a & b
}
See language reference on topic for full info.
As what such code is lowered to.
Or more pattern examples like
[var a, .., var y, _] for first and (second to last) elements
[_, >= 0, .., >=0, var z] to check & assign simultaneously
[.., [.., var zz]] to match last element of last subarray
PS Atm using stuff mentioned in first 2 examples is plenty for me.
Would be nice to have optional elements, but this already saves a lot of boilerplate.

Sorting array by length

I'm wanting to sort this array by length but how will I do that? I searched the web for a while but couldn't find anything. The code is supposed to sort an array given at random by each strings length in the string array, but I can't get anyway of declaring how I want it to sort.
public class Kata
{
public static string[] SortByLength (string[] array)
{
Array.Sort(array);
return array;
}
}
Well, in order to sort the array in place you should provide rule of sorting:
Array.Sort(array, (x, y) => x.Length.CompareTo(y.Length));
The method can be
public static string[] SortByLength (string[] array) {
//TODO: validate array and its items here; they must be not null
Array.Sort(array, (x, y) => x.Length.CompareTo(y.Length));
return array;
}
Use linq...
public static string[] SortByLength (string[] array) =>
array.OrderBy( x => x?.Length ?? 0 ).ToArray();
Dude, this is how it should work.
Array.Sort(array, StringComparer.InvariantCulture);

Why my Generic Extension Method says cannot convert from T to ..... or .... to T

Further to my questions
https://stackoverflow.com/questions/10241345/any-percentage-function-in-net
https://stackoverflow.com/questions/9942202/percentage-of-each-element-in-linq
i want to create a generic extension method in .Net 4.0 which will generate percentage of the list items to the sum of the list. This list will be of Numeric types only.
My code is
public static T Percentage<T>(this T array) where T: ? // What should come in place of ?
{
double[] darray = (double[])T; // Error convert type 'T' to 'double[]'
darray = darray.Select(x=> x * 100 / darray.Sum()).ToArray();
return darray; // Error convert type 'double[]' to 'T'
}
I want to call it like
double[] MD = {8.0,21.0,25.0,13.0,26.0,37.0,37.0,33.0,71.0,9.0};
MD = MD.Percentage().ToArray();
What am i doing wrong;
You cannot constrain types by "numeric" values. It is somewhat of a limitation of the framework.
Your best best is to do this:
public static IEnumerable<double> Percentage(this IEnumerable<int> values)
{
var sum = values.Sum();
return values.Select(v => (double)v / (double)sum).ToArray();
}
public static IEnumerable<double> Percentage(this IEnumerable<long> values)
{
var sum = values.Sum();
return values.Select(v => (double)v / (double)sum).ToArray();
}
public static IEnumerable<double> Percentage(this IEnumerable<double> values)
{
var sum = values.Sum();
return values.Select(v => v / sum).ToArray();
}
Essentially you need to produce an overload for each type you want to support.
It is not possible to have constrain of type you want. Check out Constraining a generic type argument to numeric types for details.
Since there are not too many numeric types (int/float/double/decimal) it may be easier to simply provide concrete implementations.
More options
require IConvertable and use IConvertible.ToDouble to perform all math in doubles
use https://jonskeet.uk/csharp/miscutil/usage/genericoperators.html mentioned here C#: Generic Interface for Numbers.
There is an alternative that works, which is to pass in the selector function that allows you to convert to doubles when you call Percentage. This is the extension method:
public static double[] Percentage<T>(this T[] array, Func<T,double> selector)
{
var doubles = array.Select(selector);
var sum = doubles.Sum();
var result = doubles.Select(x => x * 100 / sum).ToArray();
return result;
}
Usage:
double[] MD = {8.0,21.0,25.0,13.0,26.0,37.0,37.0,33.0,71.0,9.0};
var MDPercent = MD.Percentage(x => x).ToArray();
And then you can have a simple double version:
public static double[] Percentage(this double[] array)
{
return Percentage(array, x => x);
}
Or an int version:
public static double[] Percentage(this int[] array)
{
return array.Percentage(x => (double)x);
}
Which are simpler to use:
var MDPercent = MD.Percentage().ToArray();

Get next N elements from enumerable

Context: C# 3.0, .Net 3.5
Suppose I have a method that generates random numbers (forever):
private static IEnumerable<int> RandomNumberGenerator() {
while (true) yield return GenerateRandomNumber(0, 100);
}
I need to group those numbers in groups of 10, so I would like something like:
foreach (IEnumerable<int> group in RandomNumberGenerator().Slice(10)) {
Assert.That(group.Count() == 10);
}
I have defined Slice method, but I feel there should be one already defined. Here is my Slice method, just for reference:
private static IEnumerable<T[]> Slice<T>(IEnumerable<T> enumerable, int size) {
var result = new List<T>(size);
foreach (var item in enumerable) {
result.Add(item);
if (result.Count == size) {
yield return result.ToArray();
result.Clear();
}
}
}
Question: is there an easier way to accomplish what I'm trying to do? Perhaps Linq?
Note: above example is a simplification, in my program I have an Iterator that scans given matrix in a non-linear fashion.
EDIT: Why Skip+Take is no good.
Effectively what I want is:
var group1 = RandomNumberGenerator().Skip(0).Take(10);
var group2 = RandomNumberGenerator().Skip(10).Take(10);
var group3 = RandomNumberGenerator().Skip(20).Take(10);
var group4 = RandomNumberGenerator().Skip(30).Take(10);
without the overhead of regenerating number (10+20+30+40) times. I need a solution that will generate exactly 40 numbers and break those in 4 groups by 10.
Are Skip and Take of any use to you?
Use a combination of the two in a loop to get what you want.
So,
list.Skip(10).Take(10);
Skips the first 10 records and then takes the next 10.
I have done something similar. But I would like it to be simpler:
//Remove "this" if you don't want it to be a extension method
public static IEnumerable<IList<T>> Chunks<T>(this IEnumerable<T> xs, int size)
{
var curr = new List<T>(size);
foreach (var x in xs)
{
curr.Add(x);
if (curr.Count == size)
{
yield return curr;
curr = new List<T>(size);
}
}
}
I think yours are flawed. You return the same array for all your chunks/slices so only the last chunk/slice you take would have the correct data.
Addition: Array version:
public static IEnumerable<T[]> Chunks<T>(this IEnumerable<T> xs, int size)
{
var curr = new T[size];
int i = 0;
foreach (var x in xs)
{
curr[i % size] = x;
if (++i % size == 0)
{
yield return curr;
curr = new T[size];
}
}
}
Addition: Linq version (not C# 2.0). As pointed out, it will not work on infinite sequences and will be a great deal slower than the alternatives:
public static IEnumerable<T[]> Chunks<T>(this IEnumerable<T> xs, int size)
{
return xs.Select((x, i) => new { x, i })
.GroupBy(xi => xi.i / size, xi => xi.x)
.Select(g => g.ToArray());
}
Using Skip and Take would be a very bad idea. Calling Skip on an indexed collection may be fine, but calling it on any arbitrary IEnumerable<T> is liable to result in enumeration over the number of elements skipped, which means that if you're calling it repeatedly you're enumerating over the sequence an order of magnitude more times than you need to be.
Complain of "premature optimization" all you want; but that is just ridiculous.
I think your Slice method is about as good as it gets. I was going to suggest a different approach that would provide deferred execution and obviate the intermediate array allocation, but that is a dangerous game to play (i.e., if you try something like ToList on such a resulting IEnumerable<T> implementation, without enumerating over the inner collections, you'll end up in an endless loop).
(I've removed what was originally here, as the OP's improvements since posting the question have since rendered my suggestions here redundant.)
Let's see if you even need the complexity of Slice. If your random number generates is stateless, I would assume each call to it would generate unique random numbers, so perhaps this would be sufficient:
var group1 = RandomNumberGenerator().Take(10);
var group2 = RandomNumberGenerator().Take(10);
var group3 = RandomNumberGenerator().Take(10);
var group4 = RandomNumberGenerator().Take(10);
Each call to Take returns a new group of 10 numbers.
Now, if your random number generator re-seeds itself with a specific value each time it's iterated, this won't work. You'll simply get the same 10 values for each group. So instead, you would use:
var generator = RandomNumberGenerator();
var group1 = generator.Take(10);
var group2 = generator.Take(10);
var group3 = generator.Take(10);
var group4 = generator.Take(10);
This maintains an instance of the generator so that you can continue retrieving values without re-seeding the generator.
You could use the Skip and Take methods with any Enumerable object.
For your edit :
How about a function that takes a slice number and a slice size as a parameter?
private static IEnumerable<T> Slice<T>(IEnumerable<T> enumerable, int sliceSize, int sliceNumber) {
return enumerable.Skip(sliceSize * sliceNumber).Take(sliceSize);
}
It seems like we'd prefer for an IEnumerable<T> to have a fixed position counter so that we can do
var group1 = items.Take(10);
var group2 = items.Take(10);
var group3 = items.Take(10);
var group4 = items.Take(10);
and get successive slices rather than getting the first 10 items each time. We can do that with a new implementation of IEnumerable<T> which keeps one instance of its Enumerator and returns it on every call of GetEnumerator:
public class StickyEnumerable<T> : IEnumerable<T>, IDisposable
{
private IEnumerator<T> innerEnumerator;
public StickyEnumerable( IEnumerable<T> items )
{
innerEnumerator = items.GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return innerEnumerator;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return innerEnumerator;
}
public void Dispose()
{
if (innerEnumerator != null)
{
innerEnumerator.Dispose();
}
}
}
Given that class, we could implement Slice with
public static IEnumerable<IEnumerable<T>> Slices<T>(this IEnumerable<T> items, int size)
{
using (StickyEnumerable<T> sticky = new StickyEnumerable<T>(items))
{
IEnumerable<T> slice;
do
{
slice = sticky.Take(size).ToList();
yield return slice;
} while (slice.Count() == size);
}
yield break;
}
That works in this case, but StickyEnumerable<T> is generally a dangerous class to have around if the consuming code isn't expecting it. For example,
using (var sticky = new StickyEnumerable<int>(Enumerable.Range(1, 10)))
{
var first = sticky.Take(2);
var second = sticky.Take(2);
foreach (int i in second)
{
Console.WriteLine(i);
}
foreach (int i in first)
{
Console.WriteLine(i);
}
}
prints
1
2
3
4
rather than
3
4
1
2
Take a look at Take(), TakeWhile() and Skip()
I think the use of Slice() would be a bit misleading. I think of that as a means to give me a chuck of an array into a new array and not causing side effects. In this scenario you would actually move the enumerable forward 10.
A possible better approach is to just use the Linq extension Take(). I don't think you would need to use Skip() with a generator.
Edit: Dang, I have been trying to test this behavior with the following code
Note: this is wasn't really correct, I leave it here so others don't fall into the same mistake.
var numbers = RandomNumberGenerator();
var slice = numbers.Take(10);
public static IEnumerable<int> RandomNumberGenerator()
{
yield return random.Next();
}
but the Count() for slice is alway 1. I also tried running it through a foreach loop since I know that the Linq extensions are generally lazily evaluated and it only looped once. I eventually did the code below instead of the Take() and it works:
public static IEnumerable<int> Slice(this IEnumerable<int> enumerable, int size)
{
var list = new List<int>();
foreach (var count in Enumerable.Range(0, size)) list.Add(enumerable.First());
return list;
}
If you notice I am adding the First() to the list each time, but since the enumerable that is being passed in is the generator from RandomNumberGenerator() the result is different every time.
So again with a generator using Skip() is not needed since the result will be different. Looping over an IEnumerable is not always side effect free.
Edit: I'll leave the last edit just so no one falls into the same mistake, but it worked fine for me just doing this:
var numbers = RandomNumberGenerator();
var slice1 = numbers.Take(10);
var slice2 = numbers.Take(10);
The two slices were different.
I had made some mistakes in my original answer but some of the points still stand. Skip() and Take() are not going to work the same with a generator as it would a list. Looping over an IEnumerable is not always side effect free. Anyway here is my take on getting a list of slices.
public static IEnumerable<int> RandomNumberGenerator()
{
while(true) yield return random.Next();
}
public static IEnumerable<IEnumerable<int>> Slice(this IEnumerable<int> enumerable, int size, int count)
{
var slices = new List<List<int>>();
foreach (var iteration in Enumerable.Range(0, count)){
var list = new List<int>();
list.AddRange(enumerable.Take(size));
slices.Add(list);
}
return slices;
}
I got this solution for the same problem:
int[] ints = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
IEnumerable<IEnumerable<int>> chunks = Chunk(ints, 2, t => t.Dump());
//won't enumerate, so won't do anything unless you force it:
chunks.ToList();
IEnumerable<T> Chunk<T, R>(IEnumerable<R> src, int n, Func<IEnumerable<R>, T> action){
IEnumerable<R> head;
IEnumerable<R> tail = src;
while (tail.Any())
{
head = tail.Take(n);
tail = tail.Skip(n);
yield return action(head);
}
}
if you just want the chunks returned, not do anything with them, use chunks = Chunk(ints, 2, t => t). What I would really like is to have to have t=>t as default action, but I haven't found out how to do that yet.

IEnumerable doesn't have a Count method

I have the following method:
public bool IsValid
{
get { return (GetRuleViolations().Count() == 0); }
}
public IEnumerable<RuleViolation> GetRuleViolations(){
//code here
}
Why is it that when I do .Count() above it is underlined in red?
I got the following error:
Error 1 'System.Collections.Generic.IEnumerable'
does not contain a definition for
'Count' and no extension method
'Count' accepting a first argument of
type
'System.Collections.Generic.IEnumerable'
could be found (are you missing a
using directive or an assembly
reference?) c:\users\a\documents\visual
studio
2010\Projects\NerdDinner\NerdDinner\Models\Dinner.cs 15 47 NerdDinner
You add:
using System.Linq;
at the top of your source and make sure you've got a reference to the System.Core assembly.
Count() is an extension method provided by the System.Linq.Enumerable static class for LINQ to Objects, and System.Linq.Queryable for LINQ to SQL and other out-of-process providers.
EDIT: In fact, using Count() here is relatively inefficient (at least in LINQ to Objects). All you want to know is whether there are any elements or not, right? In that case, Any() is a better fit:
public bool IsValid
{
get { return !GetRuleViolations().Any(); }
}
Any() or Count() methods in Linq work only for generic types.
IEnumerable<T>
If you have a simple IEnumerable without a type, try to use
IEnumerable<object>
instead.
IEnumeration does not have a method called Count(). It's just a kind of "sequence of elements". Use for example List if you explicitly need the number of elements.
If you use Linq keep in mind, that the extension method Count() may actually re-count the number of elements each time you call it.
A short & sweet general word of caution on the pitfalls of .Count() to help the weary traveler that stumbles upon this post in the future!
Short story:
The following works -no doubt- but there might small performance penalty if the enumerables is not backed by an underlying array or list which has the 'count' in handy/precomputed:
public bool IsValid
{
get { return SomeMethodReturningEnumerable().Count() <= threshold; } <--- small performance issue here
}
public IEnumerable<SomeObject> SomeMethodReturningEnumerable(){
yield return foo;
yield return bar; etc
}
The call to the .Count() method will probably go through each and every item in the enumerable and then compare the overall count against threshold. We being smarter can do a bit better:
public bool IsValid
{
get { return !SomeMethodReturningEnumerable().HasMoreThan(threshold); } <--- neato!
}
public static bool HasLessThan<T>(this IEnumerable<T> sequence, int count) => !sequence.HasMoreThan(count - 1);
public static bool HasLessOrEqualTo<T>(this IEnumerable<T> sequence, int count) => !sequence.HasMoreThan(count);
public static bool HasMoreOrEqualTo<T>(this IEnumerable<T> sequence, int count) => sequence.HasMoreThan(count - 1);
public static bool HasMoreThan<T>(this IEnumerable<T> sequence, int count) => sequence.EnumerationCounterImpl(count, equals_vs_greaterThan: false);
public static bool HasExactly<T>(this IEnumerable<T> sequence, int count) => sequence.EnumerationCounterImpl(count, equals_vs_greaterThan: true);
public static bool EnumerationCounterImpl<T>(this IEnumerable<T> sequence, int count, bool equals_vs_greaterThan = true) //0
{
if (equals_vs_greaterThan && count < 0)
throw new ArgumentException($"{nameof(count)} is less than zero!");
if (!equals_vs_greaterThan && count < 0)
return true;
var staticCount = (sequence as ICollection)?.Count
?? (sequence as ICollection<T>)?.Count
?? (sequence as IReadOnlyCollection<T>)?.Count;
if (staticCount != null)
return staticCount > count;
using (var enumerator = sequence.GetEnumerator()) //1 optimization
{
for (int i = 0; i < count + 1; i++)
{
if (enumerator.MoveNext())
continue;
return false;
}
return !equals_vs_greaterThan // ==
|| enumerator.MoveNext(); // >
}
//0 https://blog.slaks.net/2015-01-12/linq-count-considered-occasionally-harmful/
//1 using the enumerator directly is slightly faster than using LINQ methods it avoids allocating an extra iterator
// state machine compared to using skip()
}
There! Problem solved again but this time around we are performance-conscious!
How about:
public bool IsValid
{
get { return (GetRuleViolations().Cast<RuleViolation>().Count() == 0); }
}

Categories

Resources