我正在尝试设计一种方法(.NET 4.5.2)来快速确定int是否在数值范围内。范围不重叠。速度是此全内存操作的首要优先级。 下面的代码工作正常,但实际系统将有来自DB的500,000行,我担心在阵列中间寻找范围命中会导致性能下降。一旦从数据库中读取数据,它就会保留在内存中,并用作Web应用程序中的参考数据。
所有想法都赞赏。感谢Filter方法的https://stackoverflow.com/a/5612589/139618。
// Running console app correctly shows "2288779".
static void Main( string[] args )
{
int[,] intervals = new int[3, 3];
intervals[0, 0] = 200;
intervals[0, 1] = 250;
intervals[0, 2] = 1121214;
intervals[1, 0] = 300;
intervals[1, 1] = 350;
intervals[1, 2] = 2288779;
intervals[2, 0] = 400;
intervals[2, 1] = 450;
intervals[2, 2] = 3300004;
var seekIntA = 336;
var result = Filter(intervals, u => u[0] <= seekIntA && u[1] >= seekIntA).FirstOrDefault();
if (null != result)
{
Console.WriteLine(result[2]);
}
else
{
Console.WriteLine("null");
}
}
public static IEnumerable<T[]> Filter<T>( T[,] source , Func<T[] , bool> predicate )
{
for ( int i = 0 ; i < source.GetLength( 0 ) ; ++i )
{
T[] values = new T[source.GetLength( 1 )];
for ( int j = 0 ; j < values.Length ; ++j )
{
values[j] = source[i , j];
}
if ( predicate( values ) )
{
yield return values;
}
}
}
我愿意完全废弃数组的想法并使用任何其他集合(小写故意)类型来存储/搜索范围。
感谢。
答案 0 :(得分:3)
如果看起来你的范围是一致的,你可以用O(1)时间和记忆来计算范围。 对于更通用的,虽然复杂的解决方案:
class Range
{
public int min { get; private set; }
public int max { get; private set; }
public Range(int min, int max) {
this.min = min;
this.max = max;
}
}
class MinComparer : IComparer<Range>
{
public int Compare(Range x, Range y) {
return (x.min - y.min);
}
}
class MaxComparer : IComparer<Range>
{
public int Compare(Range x, Range y) {
return (x.max - y.max);
}
}
class Ranges
{
private List<Range> rangesMin;
private List<Range> rangesMax;
private IComparer<Range> minComparer;
private IComparer<Range> maxComparer;
public Ranges() {
minComparer = new MinComparer();
maxComparer = new MaxComparer();
rangesMin = getRanges();
rangesMax = new List<Range>(rangesMin);
rangesMin.Sort(minComparer);
rangesMax.Sort(maxComparer);
}
public IEnumerable<Range> getSetOfPossibleRanges(int numberToSeek) {
Range rangeToSeek = new Range(numberToSeek, numberToSeek);
int indexMin = rangesMin.BinarySearch(rangeToSeek, minComparer);
int indexMax = rangesMax.BinarySearch(rangeToSeek, maxComparer);
if(indexMin < 0) {
indexMin = ~indexMin;
}
if(indexMax < 0) {
indexMax = ~indexMax;
}
List<Range> subMin = rangesMin.GetRange(0, indexMin);
List<Range> subMax = rangesMax.GetRange(indexMax, rangesMax.Count - indexMax);
return subMin.Intersect(subMax);
}
private List<Range> getRanges() { //get ranges from DB here }
}
我使用了两个列表,一个按范围的下限排序,另一个按上限排序。 所有具有搜索号码的范围是这些列表的子集的交集,其中该数字大于最小排序列表中的下限,并且小于最大排序列表中的上限。
Ranges
只应在应用程序启动时初始化(在初始化时进行昂贵的排序操作)。
我针对类似于您的代码的解决方案对此进行了测试,发现它更快更多(使用1M随机范围进行测试)。