Search code examples
c#linqlinq-group

How could I LINQ's GroupBy() with a boundary?


Let's say I have a collection of elements which have a float property.

I was grouping by it but I found I was getting undesired groupings.

For example (with a double to take profit of Random's NextDouble()):

void Main()
{
    var examples = new List<Example>();
    var rnd = new Random();
    for (int i = 0; i < 100; i++)
    {
        var newPosition = rnd.NextDouble();
        examples.Add(new Example { Position = newPosition });
    }
    
    examples.GroupBy(x => x.Position).Dump();
}

class Example
{
    public double Position { get; set; }
}

This would lead into something like this:

Grouping 0,00075609376689237252

Grouping 0,0010980092925475954

Grouping 0,0020200186418462629

Grouping 0,0062832017458431429

...

Question is (worthy or not): how could I group them by allowing to have a "boundary" like... +- 0.05?


Solution

  • The boundary of +-0.05 is a bit unclear:

    For a set like : { 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1 }
    Each value is 0.01 for the next but but all are in the [+-0.05] range from 0.05.
    But 0.01 and 0.06 are too far from each other.

    But rounding to the 2nd decimal could be enought.

    examples.GroupBy(x => Math.Round( x.Position,2))
    

    As bleep-bloop commented:

    if you want to group by sets of 0,05 you could do x => Math.Round(x.Position / 0.05)

    MCVE:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    
    public class Program
    {
        public void Main()
        {
            var examples = new List<Example>();
            var rnd = new Random();
            for (int i = 0; i < 100; i++)
            {
                var newPosition = rnd.NextDouble();
                examples.Add(new Example { Position = newPosition });
            }
    
            examples.GroupBy(x => Math.Round( x.Position,2)).Dump();
    
    
            examples.GroupBy(x => x => Math.Round(x.Position / 0.05)).Dump();
        }
    
        public class Example
        {
            public double Position { get; set; }
        }
    }
    

    Live exemple : https://dotnetfiddle.net/LDNBgu