简体   繁体   English

重叠范围检查重叠

[英]Overlapping Ranges Check for Overlapping

I have a list of ranges and I would like to find out if they overlap. 我有一个范围列表,我想知道它们是否重叠。

I have the following code. 我有以下代码。 Which does not seem to be working. 哪个似乎没有用。 Is there an easier way to do this or a way that works :) 有没有更简单的方法来做到这一点或工作的方式:)

Thanks in advance for any advice. 提前感谢任何建议。

   public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private IList<Range> rangeList;

    private void Form1_Load(object sender, EventArgs e)
    {
        rangeList.Add(new Range{FromNumber = 0, ToNumber = 100});
        rangeList.Add(new Range { FromNumber = 101, ToNumber = 200 });

        // this range should over lap and throw an exception 
        rangeList.Add(new Range { FromNumber = 199, ToNumber = 300 });

    }

    private bool RangesOverlap()
    {
        var bigList = new List<List<int>>();

        foreach (var range in this.rangeList)
        {
            bigList.Add(new List<int> { range.FromNumber , range.ToNumber });
        }

        IEnumerable<IEnumerable<int>> lists = bigList;

        return lists
         .Where(c => c != null && c.Any())
         .Aggregate(Enumerable.Intersect)
         .ToList().Count > 0;
    }
}


public class Range
{
    public int FromNumber { get; set; }
    public int ToNumber { get; set; }
}

First merge numbers and then check generated list is in sorted order: 首先合并数字然后检查生成的列表是按排序顺序:

rangeList
.OrderBy(p => p.FromNumber)
.Select(p => new[] { p.FromNumber, p.ToNumber })
.SelectMany(p => p)
.Aggregate((p, q) => q >= p ? q : int.MaxValue) == int.MaxValue

In the past I faced a challenge where I had to write a validating algorithm for ranges that are created by the user (integers or reals). 在过去,我遇到了一个挑战,我必须为用户创建的范围(整数或实数)编写验证算法。 I had to check 3 things: 我必须检查3件事:

  1. Ranges are continuous 范围是连续的
  2. Ranges are not overlapping 范围不重叠
  3. LOW value must be always <= than HIGH LOW值必须始终<=高于HIGH

So I came up with the following PHP algorithm. 所以我提出了以下PHP算法。

 //Let's hardcode an array of integers (it can be of reals as well):
 $range = array
 (
     array(1, 13),
     array(14, 20),
     array(21, 45),
     array(46, 50),
     array(51, 60)
 );

 //And the validation algorithm:
 $j = 0;
 $rows = sizeof($range);
 $step = 1;   // This indicates the step of the values.
              // 1 for integers, 0.1 or 0.01 for reals

 for ($x=0; $x<$rows; $x++)
     for ($y=0; $y<$rows; $y++) {
         if ( ($range[$x][0] <= $range[$y][0]) AND ($range[$y][0] <= $range[$x][1]) AND ($x != $y) ) {
             echo "Ranges intercepting";   // replace with error handling code
             break 3;
         }
         if ( $range[$x][0] > $range[$x][1] ) {
             echo "Not valid high & low";  // replace with error handling code
             break 3;
         }
         if ( $range[$x][0] - $range[$y][1] == $step ) {
             $j++;
         }
     }
 if ( $j != $rows - $step )
     echo "Not continuous";    // replace with error handling code

We iterate through the ranges and compare them in pairs. 我们遍历范围并成对比较它们。 For each pair we: 对于每一对我们:

  1. find overlapping ranges and raise an error 找到重叠范围并引发错误
  2. find start & end points in reverse and raise an error 反向查找起点和终点并引发错误

If none of the above occurs, we count the difference of end - start points. 如果没有上述情况发生,我们计算结束起点的差异。 This number must be equals to the number of ranges minus the step (1, 0.1, 0.01, etc). 此数字必须等于范围数减去步骤(1,0.1,0.01等)。 Otherwise we raise an error. 否则我们会引发错误。

Hope this helps! 希望这可以帮助!

You can fulfill your new requirement with a slight modification of RezaArabs answer: 您可以通过略微修改RezaArabs答案来满足您的新要求:

rangeList
.Select(p => new[] { p.FromNumber, p.ToNumber })
.SelectMany(p => p.Distinct())
.Aggregate((p, q) => q >= p ? q : int.MaxValue) == int.MaxValue

The solution to this problem can be as simple as writing your own RangeList : IList<Range> whose Add() method throws an exception when the specified range overlaps with one or more ranges that are already in the collection. 解决此问题的方法可以像编写自己的RangeList : IList<Range>一样简单RangeList : IList<Range> ,当指定范围与集合中已有的一个或多个范围重叠时,其Add()方法会引发异常。

Working example: 工作范例:

class Range
{
    public int FromNumber { get; set; }
    public int ToNumber { get; set; }

    public bool Intersects(Range range)
    {
        if ( this.FromNumber <= range.ToNumber )
        {
            return (this.ToNumber >= range.FromNumber);
        }
        else if ( this.ToNumber >= range.FromNumber )
        {
            return (this.FromNumber <= range.ToNumber);
        }

        return false;
    }
}

class RangeList : IList<Range>
{
    private readonly IList<Range> innerList;

    #region Constructors

    public RangeList()
    {
        this.innerList = new List<Range>();
    }

    public RangeList(int capacity)
    {
        this.innerList = new List<Range>(capacity);
    }

    public RangeList(IEnumerable<Range> collection)
    {
        if ( collection == null )
            throw new ArgumentNullException("collection");

        var overlap = from left in collection
                      from right in collection.SkipWhile(right => left != right)
                      where left != right
                      select left.Intersects(right);

        if ( overlap.SkipWhile(value => value == false).Any() )
            throw new ArgumentOutOfRangeException("collection", "The specified collection contains overlapping ranges.");

        this.innerList = new List<Range>(collection);
    }

    #endregion

    private bool IsUniqueRange(Range range)
    {
        if ( range == null )
            throw new ArgumentNullException("range");

        return !(this.innerList.Any(range.Intersects));
    }

    private Range EnsureUniqueRange(Range range)
    {
        if ( !IsUniqueRange(range) )
        {
            throw new ArgumentOutOfRangeException("range", "The specified range overlaps with one or more other ranges in this collection.");
        }

        return range;
    }

    public Range this[int index]
    {
        get
        {
            return this.innerList[index];
        }
        set
        {
            this.innerList[index] = EnsureUniqueRange(value);
        }
    }

    public void Insert(int index, Range item)
    {
        this.innerList.Insert(index, EnsureUniqueRange(item));
    }

    public void Add(Range item)
    {
        this.innerList.Add(EnsureUniqueRange(item));
    }

    #region Remaining implementation details

    public int IndexOf(Range item)
    {
        return this.innerList.IndexOf(item);
    }

    public void RemoveAt(int index)
    {
        this.innerList.RemoveAt(index);
    }

    public void Clear()
    {
        this.innerList.Clear();
    }

    public bool Contains(Range item)
    {
        return this.innerList.Contains(item);
    }

    public void CopyTo(Range[] array, int arrayIndex)
    {
        this.innerList.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return this.innerList.Count; }
    }

    public bool IsReadOnly
    {
        get { return this.innerList.IsReadOnly; }
    }

    public bool Remove(Range item)
    {
        return this.innerList.Remove(item);
    }

    public IEnumerator<Range> GetEnumerator()
    {
        return this.innerList.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.innerList.GetEnumerator();
    }

    #endregion
}

Usage: 用法:

IList<Range> rangeList = new RangeList();

try
{
    rangeList.Add(new Range { FromNumber = 12, ToNumber = 12 });
    rangeList.Add(new Range { FromNumber = 13, ToNumber = 20 }); // should NOT overlap
    rangeList.Add(new Range { FromNumber = 12, ToNumber = 20 }); // should overlap
}
catch ( ArgumentOutOfRangeException exception )
{
    Console.WriteLine(exception.Message);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM