Creating variables from an array in C# [duplicate] - c#

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.

Related

Return the highest value in the IEnumerable<T> list collection each step using OrderByDescending

This is my first time asking a question on the site so I might not be doing this right. I need to find and return the highest values within my IEnumerable list but cannot show any duplicates. I also cannot use any copies or temporary collections, or use distinct. It must be done by first by taking the list and doing OrderByDescending.
This is what I have so far:
public static IEnumerable<T> PullMax<T> (IEnumerable<T> sourcelist) where T : IComparable
{
IEnumerable<T> list = sourcelist.OrderByDescending(item => item);
foreach (T item in list)
{
yield return item;
}
}
This is the result I get from this code:
foreach (int item in Util.PullMax(Util.GenRange(iMin, iMax).Concat(Util.GenRange(iMin + 5, iMax + 5))))
{
Console.Write($"\nMaximum Value: {item}");
}
Maximum Value: 15
Maximum Value: 14
Maximum Value: 13
Maximum Value: 12
Maximum Value: 11
Maximum Value: 10
Maximum Value: 10
Maximum Value: 9
Maximum Value: 9
Maximum Value: 8
Maximum Value: 8
Maximum Value: 7
Maximum Value: 6
Maximum Value: 5
Maximum Value: 4
Maximum Value: 3
This should be the expected results:
Maximum Value: 15
Maximum Value: 14
Maximum Value: 13
Maximum Value: 12
Maximum Value: 11
Maximum Value: 10
Maximum Value: 9
Maximum Value: 8
Maximum Value: 7
Maximum Value: 6
Maximum Value: 5
Maximum Value: 4
Maximum Value: 3
I was asked to show Util.GenRange()
public static IEnumerable<int> GenRange(int iMin, int iMax)
{
while (true)
{
for (int i = iMin; i < iMax; i++)
{
yield return i;
}
yield break;
}
}
The result I am getting has duplicates and I cannot have them. How can I get rid of them without any copies or temporary collections or even using distinct?
An approach that avoids the multiple enumeration problem with the other solution (i.e. the other solution iterates more than once over the enumerable):
public static IEnumerable<T> PullMax<T> (IEnumerable<T> sourcelist) where T : IComparable
{
IEnumerable<T> list = sourcelist.OrderByDescending(item => item);
T previousValue = default(T);
bool firstIteration = true;
foreach (T item in list)
{
if (firstIteration)
firstIteration = false;
else if (item.CompareTo(previousValue) == 0)
continue;
previousValue = item;
yield return item;
}
}
Basically it always returns the first element - then for elements other than the first it returns them only if they don't match the previous element. This will be dramatically faster for some classes of data (e.g. where sourcelist is an IQueryable) since it avoids the unnecessary counting etc.
Lots and lots of different options for writing this algorithm yourself.
However it is always better to reuse code where possible, only problem is you haven't found a LINQ method that does a Distinct Sorting in only one pass.
But there is SortedSet<T>, which is basically a sorted distinct list, and it claims O(n log n) for insertion, and can take an IEnumerable. It does not throw on duplicates, it just ignores them:
static IEnumerable<T> PullMax<T>(this IEnumerable<T> source, IComparer<T> comparer)
{
return new SortedSet<T>(source, comparer);
}
To get it to go in descending order, flip the compare result in your lambda by using a -:
list.PullMax((a, b) => -a.CompareTo(b))
You wrote:
I need to find and return the highest values within my IEnumerable list but cannot show any duplicates.
From your code, I gather that you don't want only the highest value of your input sequence, but that you want the values ordered in descending order, without any duplicates.
To make usage LINQ-like, I'll create it as an extension method. If you are not familiar with extension methods, read extension methods demystified
Extension method is merely syntactic sugar. It makes it look for the reader as if the method that you call is a method of the class.
Instead of calling a method in a static class:
var customers = FetchCustomers();
var maxCustomers = ExtraCustomerFunctions.PullMax(customers);
You can write:
var customers = FetchCustomers();
var maxCustomers = customers.PullMax();
The only thing you have to do for this, is to create a static method in a static class and use the word this before the first parameter.
Back to your question
Requirement
From the input sequence of objects of class T, which implements IComparable<T>, return a sequence with as first element the largest item, then the largest but one, etc. Discard Duplicate values.
public class MyExtensionMethods
{
public static IEnumerable<T> PullMax<T> (this IEnumerable<T> source)
where T : IComparable<T>
{
IEnumerable<T> orderedSource = source.OrderByDescending(item => item);
using (IEnumerator<T> enumerator = orderedSource.GetEnumerator())
{
if (enumerator.MoveNext())
{
// The sequence is not empty.
// return the first item, and remember that you returned this value
T lastReturnedItem = enumerator.Current;
yield return lastReturnedItem;
// enumerate the rest, skip the items with a value that you just returned
while (enumerator.MoveNext())
{
// Current is either as large as the last returned one, or it is smaller
if (enumerator.Curren.Compare(lastReturnedItem) < 0)
{
// Current is smaller; return it, and remember that you returned it
lastReturnedItem = enumerator.Current;
yield return lastReturnedItem;
}
}
}
}
}
}
This seems a lot of code, but most of it is comment.
Usage:
int[] numbers = FetchNumbers();
var pulledMaxNumbers = numbers.PullMax();
There is room for improvement!
If you intend to reuse this method, consider to make it more generic, more LINQ-like. This way it will be easy to use the method for items that are not comparable.
Customers are not comparable, but you can compare them on BirthDay, or PostCode. With only a little change it is possible to PullMax customers:
// PullMax customers, oldest Customers first:
IEnumerable<Customer> customers = this.FetchCustomers();
var result = customers.PullMax(customer => customer.BirthDay);
To do this, make a method with a property selector and a generic IComparer.
Something like this:
static IEnumerable<T> PullMax<T>(this IEnumerable<T> source)
{
return source.PullMax(item => item);
}
static IEnumerable<T> PullMax<T, TKey>(this IEnumerable<T> source,
Func<T, TKey> propertySelector)
{
return source.PullMax(propertySelector, null);
}
static IEnumerable<T> PullMax<T, TKey>(this IEnumerable<T> source,
Func<T, TKey> keySelector,
IComparer<TKey> comparer)
{
// TODO: check source and keySelector not null
if (comparer == null) comparer = Comparer<TKey>.Default;
// rest of code is similar to code above, difference: check on keySelector
IEnumerable<T> orderedSource = source.OrderByDescending(keySelector);
using (IEnumerator<T> enumerator = orderedSource.GetEnumerator())
{
if (enumerator.MoveNext())
{
T currentValue = enumerator.Current;
yield return currentValue
TKey lastKeyValue = keySelector(currentValue);
while (enumerator.MoveNext())
{
currentValue = enumerator.Current;
TKey keyValue = keySelector(currentValue);
if (comparer.Compare(keyValue, lastKeyValue) < 0)
{
yield return currentValue;
lastKeyValue = keyValue;
}
etc.
You can even put your PullMax inside a LINQ concatenation:
var result = Customers.Where(customer => customer.City == "New York")
.PullMax(customer => customer.PostCode)
.Select(customer => new
{
Id = customer.Id,
Name = customer.Name,
});
Well completely without any temporary variable or distinct there is no chance. BUT the cheapest way to solve is having ONE temporary variable for holding the LAST returned value and check for that value if its the same.
maybe this method should do the trick
public static IEnumerable<T> PullMax<T>(IEnumerable<T> sourcelist) where T : IComparable
{
IEnumerable<T> list = sourcelist.OrderByDescending(item => item);
if (sourcelist.LongCount() > 0) yield return list.ElementAt(0);
T tmp = sourcelist.ElementAt(0);
foreach (T item in list)
{
if (item.CompareTo(tmp) < 1) continue;
tmp = item;
yield return item;
}
}

Regarding evaluation of Enumerable/List [duplicate]

This question already has answers here:
Is there an IEnumerable implementation that only iterates over it's source (e.g. LINQ) once?
(4 answers)
Closed 3 years ago.
I've been playing with Lists and Enumerables and I think I understand the basics:
Enumerable: The elements are evaluated each time they are consumed.
List: The elements are evaluated on definition and are not reevaluated at any point.
I've done some tests:
Enumerable. https://www.tutorialspoint.com/tpcg.php?p=bs75zCKL
List: https://www.tutorialspoint.com/tpcg.php?p=PpyY2iif
SingleEvaluationEnum: https://www.tutorialspoint.com/tpcg.php?p=209Ciiy7
Starting with the Enumerable example:
var myList = new List<int>() { 1, 2, 3, 4, 5, 6 };
var myEnumerable = myList.Where(p =>
{
Console.Write($"{p} ");
return p > 2;
}
);
Console.WriteLine("");
Console.WriteLine("Starting");
myEnumerable.First();
Console.WriteLine("");
myEnumerable.Skip(1).First();
The output is:
Starting
1 2 3
1 2 3 4
If we add .ToList() after the .Where(...) then the output is:
1 2 3 4 5 6
Starting
I also was able to have a bit of both worlds with this class:
class SingleEvaluationEnum<T>
{
private IEnumerable<T> Enumerable;
public SingleEvaluationEnum(IEnumerable<T> enumerable)
=> Enumerable = enumerable;
public IEnumerable<T> Get()
{
if (!(Enumerable is List<T>))
Enumerable = Enumerable.ToList().AsEnumerable();
return Enumerable;
}
}
You can see the output is:
Starting
1 2 3 4 5 6
This way the evaluation is deferred until the first consumption and is not re-evaluated in the next ones. But the whole list is evaluated.
My question is: Is there a way to get this output?
Starting
1 2 3
4
In other words: I want myEnumerable.First() to evaluate only the necesary elements, but no more. And I want myEnumerable.Skip(1).First() to reuse the already evaluated elements.
EDIT: Clarification: I want that any "query" over the Enumerable applies to all the elements in the list. That's why (AFAIK) an Enumerator doesn't work.
Thanks!
LINQ is fundamentally a functional approach to working with collections. One of the assumptions is that there are no side-effects to evaluating the functions. You're violating that assumption by calling Console.Write in the function.
There's no magic involved, just functions. IEnumerable has just one method - GetEnumerator. That's all that is needed for LINQ, and that's all that LINQ really does. For example, a naïve implementation of Where would look like this:
public static IEnumerable<T> Where<T>(this IEnumerable<T> #this, Func<T, bool> filter)
{
foreach (var item in #this)
{
if (filter(item)) yield return item;
}
}
A Skip might look like this:
public static IEnumerable<T> Skip<T>(this IEnumerable<T> #this, int skip)
{
foreach (var item in #this)
{
if (skip-- > 0) continue;
yield return item;
}
}
That's all there is to it. It doesn't have any information about what IEnumerable is or represents. In fact, that's the whole point - you're abstracting those details away. There are a few optimizations in those methods, but they don't do anything smart. In the end, the difference between the List and IEnumerable in your example isn't anything fundamental - it's that myEnumerable.Skip(1) has side-effects (because myEnumerable itself has side-effects) while myList.Skip(1) doesn't. But both do the exact same thing - evaluate the enumerable, item by item. There's no other method than GetEnumerator on an enumerable, and IEnumerator only has Current and MoveNext (of those that matter for us).
LINQ is immutable. That's one of the reasons why it's so useful. This allows you to do exactly what you're doing - query the same enumerable twice but getting the exact same result. But you're not happy with that. You want things to be mutable. Well, nothing is stopping you from making your own helper functions. LINQ is just a bunch of functions, after all - you can make your own.
One such simple extension could be a memoized enumerable. Wrap around the source enumerable, create a list internally, and when you iterate over the source enumerable, keep adding items to the list. The next time GetEnumerator is called, start iterating over your internal list. When you reach the end, continue with the original approach - iterate over the source enumerable and keep adding to the list.
This will allow you to use LINQ fully, just inserting Memoize() to your LINQ queries at the places where you want to avoid iterating over the source multiple times. In your example, this would be something like:
myEnumerable = myEnumerable.Memoize();
Console.WriteLine("");
Console.WriteLine("Starting");
myEnumerable.First();
Console.WriteLine("");
myEnumerable.Skip(1).First();
The first call to myEnumerable.First() will iterate through the first three items in myList, and the second will only work with the fourth.
Basically it sounds like you're looking for an Enumerator which you can get by calling GetEnumerator on an IEnumerable. An Enumerator keeps track of it's position.
var myList = new List<int>() { 1, 2, 3, 4, 5, 6 };
var myEnumerator = myList.Where(p =>
{
Console.Write($"{p} ");
return p > 2;
}
).GetEnumerator();
Console.WriteLine("Starting");
myEnumerator.MoveNext();
Console.WriteLine("");
myEnumerator.MoveNext();
This will get you the output:
Starting
1 2 3
4
Edit to respond to your comment:
First of all this sounds like an extremely bad idea. An enumerator represents something that can be enumerated. This is why you can pipe all those fancy LINQ queries on top of it. However all calls to First "visualize" this enumeration (which results in GetEnumerator being called to get an Enumerator and walking over that until we're done and then disposing it). You however ask for every visualization to change the IEnumerable it's visualizing (this is not good practice).
However since you said this is for learning I'll give you code that ends up with an IEnumerable that will give you your desired output. I would not recommend you ever use this in real code, this is not a good and solid way of doing things.
First we create a custom Enumerator that doesn't dispose, but just keeps enumerating some internal enumerator:
public class CustomEnumerator<T> : IEnumerator<T>
{
private readonly IEnumerator<T> _source;
public CustomEnumerator(IEnumerator<T> source)
{
_source = source;
}
public T Current => _source.Current;
object IEnumerator.Current => _source.Current;
public void Dispose()
{
}
public bool MoveNext()
{
return _source.MoveNext();
}
public void Reset()
{
throw new NotImplementedException();
}
}
Then we create a custom IEnumerable class that, instead of creating a new Enumerator everytime GetEnumerator() is called, but will secretly keep using the same enumerator:
public class CustomEnumerable<T> : IEnumerable<T>
{
public CustomEnumerable(IEnumerable<T> source)
{
_internalEnumerator = new CustomEnumerator<T>(source.GetEnumerator());
}
private IEnumerator<T> _internalEnumerator;
public IEnumerator<T> GetEnumerator()
{
return _internalEnumerator;
}
IEnumerator IEnumerable.GetEnumerator()
{
return _internalEnumerator;
}
}
And finally we create an IEnumerable extension method to convert an IEnumerable into our CustomEnumerable:
public static class IEnumerableExtensions
{
public static IEnumerable<T> ToTrackingEnumerable<T>(this IEnumerable<T> source) => new CustomEnumerable<T>(source);
}
Finally when we can now do this:
var myList = new List<int>() { 1, 2, 3, 4, 5, 6 };
var myEnumerable = myList.Where(p =>
{
Console.Write($"{p} ");
return p > 2;
}).ToTrackingEnumerable();
Console.WriteLine("Starting");
var first = myEnumerable.First();
Console.WriteLine("");
var second = myEnumerable.Where(p => p % 2 == 1).First();
Console.WriteLine("");
I changed the last part so show that we can still use LINQ on it. The output is now:
Starting
1 2 3
4 5

Linq: The "opposite" of Take?

Using Linq; how can I do the "opposite" of Take?
I.e. instead of getting the first n elements such as in
aCollection.Take(n)
I want to get everything but the last n elements. Something like
aCollection.Leave(n)
(Don't ask why :-)
Edit
I suppose I can do it this way aCollection.TakeWhile((x, index) => index < aCollection.Count - n) Or in the form of an extension
public static IEnumerable<TSource> Leave<TSource>(this IEnumerable<TSource> source, int n)
{
return source.TakeWhile((x, index) => index < source.Count() - n);
}
But in the case of Linq to SQL or NHibernate Linq it would have been nice if the generated SQL took care of it and generated something like (for SQL Server/T-SQL)
SELECT TOP(SELECT COUNT(*) -#n FROM ATable) * FROM ATable Or some other more clever SQL implementation.
I suppose there is nothing like it?
(But the edit was actually not part of the question.)
aCollection.Take(aCollection.Count() - n);
EDIT: Just as a piece of interesting information which came up in the comments - you may think that the IEnumerable's extension method .Count() is slow, because it would iterate through all elements. But in case the actual object implements ICollection or ICollection<T>, it will just use the .Count property which should be O(1). So performance will not suffer in that case.
You can see the source code of IEnumerable.Count() at TypeDescriptor.net.
I'm pretty sure there's no built-in method for this, but this can be done easily by chaining Reverse and Skip:
aCollection.Reverse().Skip(n).Reverse()
I don't believe there's a built-in function for this.
aCollection.Take(aCollection.Count - n)
should be suitable; taking the total number of items in the collection minus n should skip the last n elements.
Keeping with the IEnumerable philosphy, and going through the enumeration once for cases where ICollection isn't implemented, you can use these extension methods:
public static IEnumerable<T> Leave<T>(this ICollection<T> src, int drop) => src.Take(src.Count - drop);
public static IEnumerable<T> Leave<T>(this IEnumerable<T> src, int drop) {
IEnumerable<T> IEnumHelper() {
using (var esrc = src.GetEnumerator()) {
var buf = new Queue<T>();
while (drop-- > 0)
if (esrc.MoveNext())
buf.Enqueue(esrc.Current);
else
break;
while (esrc.MoveNext()) {
buf.Enqueue(esrc.Current);
yield return buf.Dequeue();
}
}
}
return (src is ICollection<T> csrc) ? csrc.Leave(drop) : IEnumHelper();
}
This will be much more efficient than the solutions with a double-reverse, since it creates only one list and only enumerates the list once.
public static class Extensions
{
static IEnumerable<T> Leave<T>(this IEnumerable<T> items, int numToSkip)
{
var list = items.ToList();
// Assert numToSkip <= list count.
list.RemoveRange(list.Count - numToSkip, numToSkip);
return List
}
}
string alphabet = "abcdefghijklmnopqrstuvwxyz";
var chars = alphabet.Leave(10); // abcdefghijklmnop
Currently, C# has a TakeLast(n) method defined which takes characters from the end of the string.
See here: https://msdn.microsoft.com/en-us/library/hh212114(v=vs.103).aspx

Using LINQ to create an IEnumerable<> of delta values

I've got a list of timestamps (in ticks), and from this list I'd like to create another one that represents the delta time between entries.
Let's just say, for example, that my master timetable looks like this:
10
20
30
50
60
70
What I want back is this:
10
10
20
10
10
What I'm trying to accomplish here is detect that #3 in the output table is an outlier by calculating the standard deviation. I've not taken statistics before, but I think if I look for the prevalent value in the output list and throw out anything outside of 1 sigma that this will work adequately for me.
I'd love to be able to create the output list with a single LINQ query, but I haven't figured it out yet. Currently I'm just brute forcing it with a loop.
If you are running .NET 4.0, this should work fine:
var deltas = list.Zip(list.Skip(1), (current, next) => next - current);
Apart from the multiple enumerators, this is quite efficient; it should work well on any kind of sequence.
Here's an alternative for .NET 3.5:
var deltas = list.Skip(1)
.Select((next, index) => next - list[index]);
Obviously, this idea will only be efficient when the list's indexer is employed. Modifying it to use ElementAt may not be a good idea: quadratic run-time will occur for non IList<T> sequences. In this case, writing a custom iterator is a good solution.
EDIT: If you don't like the Zip + Skip(1) idea, writing an extension such as this (untested) maybe useful in these sorts of circumstances:
public class CurrentNext<T>
{
public T Current { get; private set; }
public T Next { get; private set; }
public CurrentNext(T current, T next)
{
Current = current;
Next = next;
}
}
...
public static IEnumerable<CurrentNext<T>> ToCurrentNextEnumerable<T>(this IEnumerable<T> source)
{
if (source == null)
throw new ArgumentException("source");
using (var source = enumerable.GetEnumerator())
{
if (!enumerator.MoveNext())
yield break;
T current = enumerator.Current;
while (enumerator.MoveNext())
{
yield return new CurrentNext<T>(current, enumerator.Current);
current = enumerator.Current;
}
}
}
Which you could then use as:
var deltas = list.ToCurrentNextEnumerable()
.Select(c=> c.Next - c.Current);
You can use Ani's answer:-
var deltas = list.Zip(list.Skip(1), (current, next) => next - current);
With a super-simple implementation of the Zip extension method:-
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TSecond, TResult> func)
{
var ie1 = first.GetEnumerator();
var ie2 = second.GetEnumerator();
while (ie1.MoveNext() && ie2.MoveNext())
yield return func(ie1.Current, ie2.Current);
}
That'll work with 3.5.
This should do the trick:
static IEnumerable<int> GetDeltas(IEnumerable<int> collection)
{
int? previous = null;
foreach (int value in collection)
{
if (previous != null)
{
yield return value - (int)previous;
}
previous = value;
}
}
Now you can call your collection like this:
var masterTimetable = GetMasterTimeTable();
var deltas = GetDeltas(masterTimetable);
It's not really LINQ, but will effectively do the trick.
It looks like there are sufficient answers to get you going already, but I asked a similar question back in the spring:
How to zip one ienumerable with itself
In the responses to my question, I learned about "Pairwise" and "Pairwise"
As I recall, explicitly implementing your own "Pairwise" enumerator does mean that you iterate through you list exactly once whereas implementing "Pairwise" in terms of .Zip + .Skip(1) means that you will ultimately iterate over your list twice.
In my post I also include several examples of geometry (operating on lists of points) processing code such as Length/Distance, Area, Centroid.
Not that I recommend this, but totally abusing LINQ the following would work:
var vals = new[] {10, 20, 30, 50, 60, 70};
int previous = 0;
var newvals = vals.Select(i =>
{
int dif = i - previous;
previous = i;
return dif;
});
foreach (var newval in newvals)
{
Console.WriteLine(newval);
}
One liner for you:
int[] i = new int[] { 10, 20, 30, 50, 60, 70 };
IEnumerable<int> x = Enumerable.Range(1, i.Count()-1).Select(W => i[W] - i[W - 1]);
LINQ is not really designed for what you're trying to do here, because it usually evaluates value by value, much like an extremely efficient combination of for-loops.
You'd have to know your current index, something you don't, without some kind of workaround.

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.

Categories

Resources