Sacamoto
Sacamoto

Reputation: 127

check discontinuity of multiple ranges in a list

I would like to ask you if there's a way by Linq to check discontinuity of multiple ranges, for example we have a class AgeRange:

public class AgeRange
{
public int firstValue {get;set;}
public int secondValue {get;set;}
} 
var ageRange1 = new AgeRange(0,2); // interval [0,2]
var ageRange2 = new AgeRange(4,10); // interval [4,10]
var ageRange3 = new AgeRange(11,int.MaxValue); // interval [11,+oo[

var ageRangeList = new List<AgeRange>();
ageRangeList.Add(ageRange1);
ageRangeList.Add(ageRange2);
ageRangeList.Add(ageRange3);

in this example we have a discontinuity between first range and second range. is there a way in Linq to check discontinuity between elements in ageRangeList ? Thanks for you help.

Upvotes: 0

Views: 297

Answers (2)

J&#243;zef Podlecki
J&#243;zef Podlecki

Reputation: 11293

If you want to find first discontinuity and use that information elsewhere

public static IEnumerable<AgeRange> FindDiscontinuity(List<AgeRange> ageRangeList) {
        foreach(var ageRange in ageRangeList.Zip(ageRangeList.Skip(1), (a, b) => new {Prev = a, Current = b})) {

            if(ageRange.Prev.SecondValue != ageRange.Current.FirstValue) {
                yield return ageRange.Prev;
                yield return ageRange.Current;
                break;
            }
        }
    }

public static void Main()
{
        var ageRange1 = new AgeRange(0, 2);
        var ageRange2 = new AgeRange(4, 10);
        var ageRange3 = new AgeRange(11, int.MaxValue);

        var ageRangeList = new List<AgeRange>();
        ageRangeList.Add(ageRange1);
        ageRangeList.Add(ageRange2);
        ageRangeList.Add(ageRange3);
        var result = FindDiscontinuity(ageRangeList);

        foreach(var ageRange in result) {
            Console.WriteLine("{0}, {1}", ageRange.FirstValue, ageRange.SecondValue);
        }
}

You can change the function so it can return boolean value instead of data.

Upvotes: 0

Guru Stron
Guru Stron

Reputation: 142833

Assuming firstValue always <= secondValue (for the same element), you can try to use Aggregate:

var start = ageRangeList
    .OrderBy(a => a.firstValue).Dump()
    .First();
var result = ageRangeList
    .OrderBy(a => a.firstValue)
    .Aggregate(
        (hasGap: false, s: start.secondValue),
        (tuple, range) =>
        {
            if (tuple.hasGap)
            {
                return tuple;
            }
            else
            {
                var max = Math.Max(tuple.s, tuple.s+1); //hacky overflow protection
                if (max < range.firstValue)
                {
                    return (true, tuple.s);
                }
                else
                {
                    return (false,  Math.Max(tuple.s, range.secondValue));
                }
            }

        })
.hasGap;

The downside of such approach is that it still will need to loop through all age ranges.

Upvotes: 1

Related Questions