【问题标题】:Overlapping Ranges Check for Overlapping重叠范围检查重叠
【发布时间】:2015-12-13 19:54:00
【问题描述】:

我有一个范围列表,我想知道它们是否重叠。

我有以下代码。这似乎不起作用。有没有更简单的方法或可行的方法:)

提前感谢您的任何建议。

   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; }
}

【问题讨论】:

  • 感觉这应该是一个新问题,而不是现有问题的赏金。 Stack Overflow 并不能很好地处理随时间演变的问题——这对回答最初问题的人是不公平的,因为后来出现的任何人都会认为他们错过了重点。 (另外,我不知道其他人,但我不明白赏金中指定的要求......)
  • 除了提交的答案之外,我想您可能对您描述的问题基本上是“线段相交”问题的一个实例感兴趣,最常见的是使用“扫描线算法”解决。也许阅读更多内容可以为您进一步的问题提供答案。

标签: c# .net list range intersect


【解决方案1】:

首先合并数字,然后检查生成的列表是否按排序顺序:

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

【讨论】:

  • 如果单个范围的 To 和 From 可以相等但在多个范围上不重叠。我们需要如何改变这一点? rangeList.Add(new Range{FromNumber = 12, ToNumber = 12}); rangeList.Add(new Range { FromNumber = 13, ToNumber = 20 });
  • @Jeepers:我认为这对 RezaArab 有点不公平,因为他给了你一个很好的答案。现在您正在添加一个额外的问题,这可能意味着 RezaArab 失去了他接受的答案。
  • 请注意:此解决方案的工作前提是rangeList 由range.FromNumber 成员按升序排序。如果它可能不是真的,只需使用rangeList.OrderBy(p =&gt; p.FromNumber).Select(...
【解决方案2】:

过去,我面临一个挑战,我必须为用户创建的范围(整数或实数)编写验证算法。我必须检查 3 件事:

  1. 范围是连续的
  2. 范围不重叠
  3. LOW 值必须始终

于是我想出了下面的 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

我们遍历范围并成对比较它们。对于每一对,我们:

  1. 查找重叠范围并引发错误
  2. 反向查找起点和终点并引发错误

如果以上都没有发生,我们计算终点-起点的差值。此数字必须等于范围数减去步长(1、0.1、0.01 等)。否则我们会报错。

希望这会有所帮助!

【讨论】:

    【解决方案3】:

    您可以通过稍微修改 RezaArabs 答案来满足您的新要求:

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

    【讨论】:

      【解决方案4】:

      此问题的解决方案可以简单到编写自己的RangeList : IList&lt;Range&gt;,当指定范围与集合中已有的一个或多个范围重叠时,其Add() 方法会引发异常。

      工作示例:

      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
      }
      

      用法:

      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);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-06-30
        • 2011-02-02
        • 1970-01-01
        • 1970-01-01
        • 2018-05-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多