Linq - Locally Great

Linq is pretty powerful, but sometimes I can find myself to do extensions, and later I wonder if I can do this with my own methods.

So, is it possible to implement the following without using the extension?

/// <summary> /// Removes duplicates that are immediately clustered together. /// </summary> public static IEnumerable<TData> DistinctLocal<TData>(this IEnumerable<TData> enumerable) { bool yielded = false; TData last = default(TData); foreach (var item in enumerable) { if (yielded == false || last.Equals(item) == false) { last = item; yielded = true; yield return item; } } } 
+6
source share
3 answers

Here's how to do it in a simple LINQ:

 int[] source = new[] { 3, 6, 1, 8, 4, 1, 1, 1, 7, 4, 2, 2 }; var result = source.Where((x, i) => i == 0 || !x.Equals(source.ElementAt(i - 1))); 

However, this code should be used only when the base sequence implements an effective index to handle the call to ElementAt , ideally O (1) times. This usually applies to implementations of IList<T> , such as arrays, but not to other collections, such as LinkedList<T> .

In addition, if you need to regularly use this functionality, there is nothing wrong with defining an extension method that is more convenient than scattering this code (or any equivalent) throughout. I personally would prefer to use my own extension method to avoid the risk of performance issues for non-indexed collections.

+4
source

There is no built-in method that will give you exactly the functionality you want, but obviously you can combine the solution using only LINQ and some hacker code.

However . An extension method with a good descriptive name will be much better than (ab) using built-in methods or functions to give you this. My advice: use the extension method.

However, here's a non-extension method hacker way to get the same results, you can check this in LINQPad :

 void Main() { var source = new[] { 1, 2, 3, 3, 2, 2, 3, 3, 1, 3, 1, 1 }; int? prev = null; (from value in source where !prev.HasValue || prev.Value != value let dummy = prev = value select value).Dump(); } 
+2
source

You can use Aggregate :

 source.Aggregate(new List<YourType>(), (items, current) => { if (!items.Any() || items.Last() != current) items.Add(current); return items; }); 

But obviously, it will consume your sequence so that you lose laziness ...

+2
source

Source: https://habr.com/ru/post/955242/


All Articles