Reputation: 43
I need to group objects in proximity to each other by class property. Suppose I want to group my list data by s.Start with a threshold of 3.
data.GroupByProximity(s => s.Start, 3);
The basic class
List<Threat> data = new List<Threat>
{
new Threat{Name = "1",Source=1, Start=182},
new Threat{Name = "T2", Source=2, Start=183},
new Threat{Name = "5", Source=3, Start=181},
new Threat{Name = "7",Source=1, Start=282},
new Threat{Name = "T6", Source=2, Start=283},
new Threat{Name = "TT", Source=3, Start=281}
};
I think this is very similar to the post (LINQ (Or pseudocode) to group items by proximity), but I cannot figure out how to apply it in this case where the query is instantiating to ThreatClass.
public static IEnumerable<IGrouping<TKey, TSource>> GroupByProximity<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, int threshold) where TSource : class
{
var g = new List<TSource>();
foreach (var x in source)
{
if ((g.Count != 0) && (x > g[0] + threshold))
{
yield return (IGrouping<TKey, TSource>)g;
g = new List<TSource>();
}
g.Add(x);
}
yield return (IGrouping<TKey, TSource>)g;
}
Upvotes: 0
Views: 95
Reputation: 32266
You're close, but here's how you can convert the method from that other question to work with a collection of items given a function that returns the int
value to do the comparison with.
static IEnumerable<IEnumerable<T>> GroupByProximity<T>(
this IEnumerable<T> source,
Func<T, int> selector,
int threshold)
{
var g = new List<T>();
foreach (var x in source)
{
if ((g.Count != 0) && (selector(x) > selector(g[0]) + threshold))
{
yield return g;
g = new List<T>();
}
g.Add(x);
}
yield return g;
}
It should be noted that this relies on the original list being in order so you'd want to do
var result = data.OrderBy(x => x.Start).GroupByProximity(x => x.Start, 3);
or the ordering could be put into the method
foreach(var x in source.OrderBy(selector))
Upvotes: 1