Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 查找序列中缺失和重叠的数字_C#_Linq_Range_Sequence - Fatal编程技术网

C# 查找序列中缺失和重叠的数字

C# 查找序列中缺失和重叠的数字,c#,linq,range,sequence,C#,Linq,Range,Sequence,假设我们有这样一个数据结构: var sequences = new List<Tuple<int, int>> { new Tuple<int, int>(1, 10), new Tuple<int, int>(8, 101), new Tuple<int, int>(102, 103

假设我们有这样一个数据结构:

var sequences = new List<Tuple<int, int>>
                {
                    new Tuple<int, int>(1, 10),
                    new Tuple<int, int>(8, 101),
                    new Tuple<int, int>(102, 103),
                    new Tuple<int, int>(104, 104),
                    new Tuple<int, int>(110, 200)
                };
var序列=新列表
{
新元组(1,10),
新元组(8101),
新元组(102103),
新元组(104104),
新元组(110200)
};
我想从这个集合中得到两个结果:

  • 所有缺失的数字(在本例中:105、106、107、108、109)
  • 所有重叠的数字(在本例中:8、9、10)
我可以用几个循环和助手集合编写一个算法。这当然是可行的,但我想知道这是否可以通过LINQ和/或其他更简单、更短的算法来实现

编辑: 上面例子中的数据结构表示5个序列,第一个包含1到10的数字,第二个包含8到101的数字,依此类推。。。因为在生产中,序列可能要大得多(高达数百万),它们不是用实际集合(例如,用包含所有数字的列表)表示的,而是用元组表示的,元组表示每个序列的最小和最大数量

你可以通过

var missing = 
      Enumerable.Range(1, 200)
               .Where(i => sequences.All(t => t.Item1 > i || t.Item2 < i));
var overlapping = 
      Enumerable.Range(1, 200)
                .Where(i => sequences.Count(t => t.Item1 <= i && t.Item2 >= i) > 1);
var缺失=
可枚举范围(1200)
其中(i=>sequences.All(t=>t.Item1>i | | t.Item2sequences.Count(t=>t.Item1=i)>1);

我知道这个问题的算法(它是伪代码)。(复杂性类
O(nlog(n))
其中n是元组计数)

因此,解决方案是按函数对元组排序:

  int comparer( Tuple a, Tuple b) {
      if ( a.first.compareTo(b.first) == 0 ) {
          return a.second.compareTo(b.second);
      } else 
          return a.first.compareTo(b.first);
  }
因此,示例元组:(1,10)、(1,5)、(2,8)将排序为: (1,5),(1,10),(2,8)

下一步是累积这个结果。迭代此结果并:

 Tuple result = SortedList[0];
 foreach ( Tuple tuple in SortedList ) {

     if ( result.second < tuple.first ) {

        // here you have missing number (result.second, tuple.first)

        result.first = tuple.first; 
        result.second = tuple.second
     } else if ( result.second > tuple.first ) {

        // here you have overlapping number (tuple.first, min( result.second,tuple.second ))

        if ( result.second < tuple.second ) {
              result.second = tuple.second;
        }
     } else {
        result.second = tuple.second;
     }

 }
Tuple result=SortedList[0];
foreach(SortedList中的元组){
if(result.secondtuple.first){
//这里有重叠的数字(tuple.first,min(result.second,tuple.second))
if(result.second
我们知道,若将迭代下一个元组,则第一个数字大于或等于result.first。代码中的注释告诉您哪里有重叠和缺失的数字

试试这个

var expandedSequences = sequences.Select(t => Enumerable.Range(t.Item1, t.Item2-t.Item1)).SelectMany(t => t).OrderBy(i => i);
var dupes = expandedSequences.GroupBy(i => i).Where(g => g.Count() > 1).Select(g => g.Key);
var missing = Enumerable.Range(expandedSequences.Min(), expandedSequences.Max()).Except(expandedSequences);
一次性:

var sequences = new List<Tuple<int, int>>
    {
        new Tuple<int, int>(1, 10),
        new Tuple<int, int>(8, 101),
        new Tuple<int, int>(102, 103),
        new Tuple<int, int>(104, 104),
        new Tuple<int, int>(110, 200)
    };
var missing = new List<int>();
var overlap = new List<int>();

sequences.Aggregate((prev, current) => {
    if (prev.Item2 >= current.Item1) {
        overlap.AddRange(Enumerable.Range(current.Item1, prev.Item2 - current.Item1 + 1));
    }
    if (current.Item1 > prev.Item2 + 1) {
        missing.AddRange(Enumerable.Range(prev.Item2 + 1, current.Item1 - prev.Item2 - 1));
    }
    return current;
});
var序列=新列表
{
新元组(1,10),
新元组(8101),
新元组(102103),
新元组(104104),
新元组(110200)
};
var missing=新列表();
var overlap=新列表();
序列.聚合((上一个,当前)=>{
如果(上一个项目2>=当前项目1){
重叠.AddRange(可枚举的.Range(current.Item1,prev.Item2-current.Item1+1));
}
如果(当前项目1>上一个项目2+1){
缺少.AddRange(可枚举的.Range(prev.Item2+1,current.Item1-prev.Item2-1));
}
回流;
});

我只能假设您希望如何处理一些边缘情况。我选择不处理其中一个(在代码中注释)。由于您没有给出如何表示缺失/重映射序列的指示,因此我选择了自己的格式,使用元组来标识序列的开始和结束

//Assumes they are sorted on item1
        Tuple<IEnumerable<Tuple<int,int>>,IEnumerable<Tuple<int,int>>> FindMissingAndOverLapping(IEnumerable<Tuple<int,int>> sequences){
            var previous = Tuple.Create(0, 0);
            var missing = new List<Tuple<int,int>>();
            var overlapping = new List<Tuple<int, int>>();
            var max = 0;
            foreach (var sequence in sequences){
                var end = previous.Item2;
                max = end > max ? end : max;
                if (previous.Item2 < sequence.Item1 + 1){
                    missing.Add(Tuple.Create(previous.Item2 + 1, sequence.Item1 - 1));
                } else if (max < sequence.Item1){
                    overlapping.Add(Tuple.Create(sequence.Item1, max));
                }
            }
            //The sequences in ovrelapping can be ovrelapping them self
            return new Tuple<IEnumerable<Tuple<int,int>>,IEnumerable<Tuple<int,int>>>(missing, overlapping);
        }
//假定它们按项1排序
元组查找和覆盖(IEnumerable序列){
var previous=Tuple.Create(0,0);
var missing=新列表();
var重叠=新列表();
var max=0;
foreach(序列中的var序列){
var end=先前的.Item2;
最大值=结束>最大值?结束:最大值;
如果(先前的.Item2
我不明白你为什么叫8、9和10“重叠号码”。我不明白你为什么打105、106、107、108、109个丢失的号码-1序列不是连续的-缺失number@Matt艾伦:元组中的数字代表序列中的第一个和最后一个数字,因此序列
1..10
与序列
8..101
重叠,在序列
104..104
110..120
@Matt EllenБ之间存在一个间隙:我假设每个元组的第一个和第二个数字代表一个包含的数字范围的上下限。8、9和10是“重叠”的,因为它们同时包含在第一个范围(1到10)和第二个范围(8到101)中。105、106、107、108和109“缺失”,因为它们不包括在任何范围内。很漂亮-正是我所寻找的:)但是你需要知道序列范围的上下限。。。失败原因:var list=new list{new Tuple(-1000,0),new Tuple(10,1000)};是的,我已经将下限和上限设置为正确的值(-10001000)。缺少值的列表为空。对于每个可能值或(2*)N*M,它将迭代整个元组列表两次,其中N是可能值的数量,M是元组的数量。有数以百万计的可能值,我会说这是大量的迭代@sven:您需要使用
可枚举的.Range(-10002000)
。第一个是第一个数字,第二个是