C# 实现自定义Int+;范围列表解决方案
我想知道是否有人能想出一种方法,以一种更节省内存的方式实现一个数字数组,从而自动将其组织到各个范围中。榜样C# 实现自定义Int+;范围列表解决方案,c#,list,range,C#,List,Range,我想知道是否有人能想出一种方法,以一种更节省内存的方式实现一个数字数组,从而自动将其组织到各个范围中。榜样 List testList = new List{1,2,3,4,5,6,7...}; vs 特定于我的实施的详细信息 在我的特殊情况下,我正在逐行分析一个非常大的文档。需要识别满足特定标准的行,然后向用户显示行索引的总体列表 显然,显示“第33-32019行已识别”比显示“第33、34、35行……等”更可取。在这种情况下,数字总是正的。我要做的第一件事是创建一个代表您的范围的类。您可以
List testList = new List{1,2,3,4,5,6,7...};
vs
特定于我的实施的详细信息
在我的特殊情况下,我正在逐行分析一个非常大的文档。需要识别满足特定标准的行,然后向用户显示行索引的总体列表
显然,显示“第33-32019行已识别”比显示“第33、34、35行……等”更可取。在这种情况下,数字总是正的。我要做的第一件事是创建一个代表您的范围的类。您可以提供一些便利,比如将格式设置为字符串,以及从int进行隐式转换(这有助于以后实现范围列表) 然后可以开始执行
范围列表的简单实现。通过提供Add
方法,您可以使用类似于list
的列表初始值设定项:
这方面的实例:
接下来要做的事情是提供一个重载Add
,它接受一个int并找到正确的范围或添加一个新的范围。一个简单的实现可能如下所示(假设在范围上添加了Update
方法)
每次更改列表后都需要调用此函数
public void Add(Range range)
{
this.ranges.Add(range);
SortAndMerge();
}
public void Add(int value)
{
// is it within or contiguous to an existing range
foreach(var range in ranges)
{
if(value>=range.Start && value<=range.End)
return; // already in a range
if(value == range.Start-1)
{
range.Update(value,range.End);
SortAndMerge();
return;
}
if(value == range.End + 1)
{
range.Update(range.Start,value);
SortAndMerge();
return;
}
}
// not in any ranges
ranges.Add(value);
SortAndMerge();
}
public void Add(范围)
{
this.ranges.Add(范围);
SortAndMerge();
}
公共void Add(int值)
{
//它是在现有范围内还是邻近现有范围
foreach(范围中的var范围)
{
如果(value>=range.Start&&value)您的数字是负数吗?还是符号位为“备用”我认为这在很大程度上取决于类的使用。如果你很少添加/删除新的项目,我会把它重点放在获取/计算/任意的性能上,以及在添加项目时总是关注添加/组织的性能。我想这个问题有点太宽泛了。有很多事情要考虑。:如何表示范围
(元组,额外类型)?列表通常包含相同类型的元素,因此您需要考虑是否要将单个整数添加为长度为1的范围
…可能需要(隐式)将运算符从int
转换为Range
…您需要为列表实现一个枚举器来枚举包含的范围…这是一个有趣的想法,但意味着要为您编写大量代码…所以我仍然认为它太宽泛了。@MatthewWatson问得好,总是肯定的。请参阅我的更新。@RenéVogt我明白您的观点。然而,我可以人为地限制这个问题,使其更加具体,但我认为这不会有帮助。我已经在我的用例描述中添加了,如果这使它更“真实”。这与我的想法非常相似,但是请注意,您还必须提供更新现有范围的方法(因此,将起点和终点设为私有setter是错误的)或将其替换为新的范围(请注意,这在问题中是特别需要的).别忘了处理合并-假设您已经有1..10和12..20,然后添加11@windowskm我想给你写一个更好的Add
,它勾选了所有的框…但是我的大楼里的火警刚刚响了:D可能是个延迟!哇,绝对不是紧急的,所以别担心。保重,希望一切都好。@windowskm哈,没问题。仍然没有疏散。高层办公室的乐趣。无论如何,我更新了我的答案。如果有任何问题,请告诉我
RangeList rangeList = new RangeList{1, 4, 7-9};
rangeList.Add(2);
//rangeList -> 1-2, 4, 7-9
rangeList.Add(3);
//rangeList -> 1-3, 4, 7-9
public class Range
{
public int Start{get; private set;}
public int End{get; private set;}
public Range(int startEnd) : this(startEnd,startEnd)
{
}
public Range(int start, int end)
{
this.Start = start;
this.End = end;
}
public static implicit operator Range(int i)
{
return new Range(i);
}
public override string ToString()
{
if(Start == End)
return Start.ToString();
return String.Format("{0}-{1}",Start,End);
}
}
public class RangeList : IEnumerable<Range>
{
private List<Range> ranges = new List<Range>();
public void Add(Range range)
{
this.ranges.Add(range);
}
public IEnumerator<Range> GetEnumerator()
{
return this.ranges.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator(){
return this.GetEnumerator();
}
}
var rangeList = new RangeList(){
new Range(1,10),
15
};
foreach(var range in rangeList)
Console.WriteLine(range);
// Outputs:
// 1-10
// 15
public void Add(int i)
{
// is it within or contiguous to an existing range
foreach(var range in ranges)
{
if(i>=range.Start && i<=range.End)
return; // already in a range
if(i == range.Start-1)
{
range.Update(i,range.End);
return;
}
if(i == range.End + 1)
{
range.Update(range.Start,i);
return;
}
}
// not in any ranges
ranges.Add(i);
}
private void SortAndMerge()
{
ranges.Sort((a,b) => a.Start - b.Start);
var i = ranges.Count-1;
do
{
var start = ranges[i].Start;
var end = ranges[i-1].End;
if(end == start-1)
{
// merge and remove
ranges[i-1].Update(ranges[i-1].Start,ranges[i].End);
ranges.RemoveAt(i);
}
} while(i-- >1);
}
public void Add(Range range)
{
this.ranges.Add(range);
SortAndMerge();
}
public void Add(int value)
{
// is it within or contiguous to an existing range
foreach(var range in ranges)
{
if(value>=range.Start && value<=range.End)
return; // already in a range
if(value == range.Start-1)
{
range.Update(value,range.End);
SortAndMerge();
return;
}
if(value == range.End + 1)
{
range.Update(range.Start,value);
SortAndMerge();
return;
}
}
// not in any ranges
ranges.Add(value);
SortAndMerge();
}
public void Add(Range rangeToAdd)
{
var mergableRange = new List<Range>();
foreach (var range in ranges)
{
if (rangeToAdd.Start == range.Start && rangeToAdd.End == range.End)
return; // already exists
if (mergableRange.Any())
{
if (rangeToAdd.End >= range.Start - 1)
{
mergableRange.Add(range);
continue;
}
}
else
{
if (rangeToAdd.Start >= range.Start - 1
&& rangeToAdd.Start <= range.End + 1)
{
mergableRange.Add(range);
continue;
}
if (range.Start >= rangeToAdd.Start
&& range.End <= rangeToAdd.End)
{
mergableRange.Add(range);
continue;
}
}
}
if (!mergableRange.Any()) //Standalone range
{
ranges.Add(rangeToAdd);
}
else //merge overlapping ranges
{
mergableRange.Add(rangeToAdd);
var min = mergableRange.Min(x => x.Start);
var max = mergableRange.Max(x => x.End);
foreach (var range in mergableRange) ranges.Remove(range);
ranges.Add(new Range(min, max));
}
SortAndMerge();
}