C# 基于范围数据查找值

C# 基于范围数据查找值,c#,.net,C#,.net,什么样的数据结构或数据类型适合保存数据范围,并基于该范围内的数据返回值 例如,假设我有以下范围 1-10 -> 1 11-35 -> 2.5 36-49-> 3.8 50-60 -> 1.2 61-80 -> 0.9 在这种情况下,给定编号41我希望返回编号3.8(因为41介于36和49之间) 为了执行此查找,是否有一种在数据结构中表示此类数据的巧妙方法?您可以使用此代码 关键: 公共类间隔,其中T:i可比较 { 公共可为空的开始{get;set

什么样的数据结构或数据类型适合保存数据范围,并基于该范围内的数据返回值

例如,假设我有以下范围

1-10 -> 1  
11-35 -> 2.5  
36-49-> 3.8  
50-60 -> 1.2  
61-80 -> 0.9 
在这种情况下,给定编号
41
我希望返回编号
3.8
(因为41介于36和49之间)

为了执行此查找,是否有一种在数据结构中表示此类数据的巧妙方法?

您可以使用此代码

关键:

公共类间隔,其中T:i可比较
{
公共可为空的开始{get;set;}
公共可为空的结尾{get;set;}
公共间隔(T开始,T结束)
{
开始=开始;
结束=结束;
}
公共布尔值范围(T值)
{
返回((!Start.HasValue | | value.CompareTo(Start.value)>0)&&
(!End.HasValue | | End.Value.CompareTo(Value)>0));
}
}
值:十进制

您可以使用以下类型:
Dictionary

备注:您可以定义访问方法

您可以使用此代码

关键:

公共类间隔,其中T:i可比较
{
公共可为空的开始{get;set;}
公共可为空的结尾{get;set;}
公共间隔(T开始,T结束)
{
开始=开始;
结束=结束;
}
公共布尔值范围(T值)
{
返回((!Start.HasValue | | value.CompareTo(Start.value)>0)&&
(!End.HasValue | | End.Value.CompareTo(Value)>0));
}
}
值:十进制

您可以使用以下类型:
Dictionary


注:您可以定义访问方法

一个相对方便且性能非常好的实现是使用
分类列表
。使用每个段的下限作为键,并使用上限+映射值的元组作为值:

var list = new SortedList<int, Tuple<int, double>>
{
    { 1, Tuple.Create(10, 1.0) },
    { 11, Tuple.Create(35, 2.5) },
};
此时,
索引
指向可能包含
值的唯一范围,因此剩下的就是测试:

if(x >= list.Keys[index] && x <= list.Values[index].Item1) {
    var result = list.Values[index].Item2;
}
else {
    // no match
}

if(x>=list.Keys[index]&&x一个相对方便且性能非常好的实现是使用
SortedList
。使用每个段的下界作为键,使用上界+映射值的元组作为值:

var list = new SortedList<int, Tuple<int, double>>
{
    { 1, Tuple.Create(10, 1.0) },
    { 11, Tuple.Create(35, 2.5) },
};
此时,
索引
指向可能包含
值的唯一范围,因此剩下的就是测试:

if(x >= list.Keys[index] && x <= list.Values[index].Item1) {
    var result = list.Values[index].Item2;
}
else {
    // no match
}

if(x>=list.Keys[index]&&x我花了一段时间,但我有一个QuickAndDirty方法,它假设所有给定的值都有效,范围相邻,而不使用任何数据结构。
以及一个非常特定的数据结构,它只会在给定的索引正好在指定范围内时返回某些内容,并且可以在运行时进行扩展

public abstract class TreeNode
{
    public static double QuickAndDirty(int index)
    {
        double result = 1.0;

        if (index > 10)
            result = 2.5;

        if (index > 35)
            result = 3.8;

        if (index > 49)
            result = 1.2;

        if (index > 60)
            result = 0.9;

        return result;
    }

    public abstract double GetValue(int index);

    public abstract TreeNode AddRange(int begin, int end, double value);

    public static TreeNode MakeTreePart(Tuple<int, int, double>[] ranges)
    {
        return TreeNode.MakeTreePart(ranges, 0, ranges.Length >> 1, ranges.Length - 1);
    }

    private static TreeNode MakeTreePart(Tuple<int, int, double>[] ranges, int min, int index, int max)
    {
        if (index == min || index == max)
            return new Leaf(ranges[index].Item1, ranges[index].Item2, ranges[index].Item3);

        return new SegmentTree(
            ranges[index].Item2 + .5,
            TreeNode.MakeTreePart(ranges, min, index >> 1, index - 1),
            TreeNode.MakeTreePart(ranges, index + 1, index << 1, max));
    }
}

public class SegmentTree : TreeNode
{
    private double pivot;
    private TreeNode left, right;

    public SegmentTree(double pivot, TreeNode left, TreeNode right)
    {
        this.pivot = pivot;
        this.left = left;
        this.right = right;
    }

    public override double GetValue(int index)
    {
        if (index < pivot)
            return left.GetValue(index);
        return right.GetValue(index);
    }

    public override TreeNode AddRange(int begin, int end, double value)
    {
        if (end < pivot)
            this.left = this.left.AddRange(begin, end, value);
        else
            this.right = this.right.AddRange(begin, end, value);
        // Do this to confirm to the interface.
        return this;
    }
}

public class Leaf : TreeNode
{
    private int begin, end;
    private double value;

    public Leaf(int begin, int end, double value)
    {
        this.begin = begin;
        this.end = end;
        this.value = value;
    }

    public override double GetValue(int index)
    {
        if (index >= begin && index <= end)
            return value;
        throw new Exception("index out of range");
    }

    public override TreeNode AddRange(int begin, int end, double value)
    {
        if (this.end < begin)
            return new SegmentTree(((double)this.end + begin) * .5, this, new Leaf(begin, end, value));
        else if (end < this.begin)
            return new SegmentTree(((double)end + this.begin) * .5, new Leaf(begin, end, value), this);
        else throw new Exception("Indexes overlap.");
    }
}
    static void Main()
    {
        TreeNode start = new Leaf(36, 49, 3.8);
        start = start.AddRange(11, 35, 2.5);
        start = start.AddRange(1, 10, 1.0);
        start = start.AddRange(50, 60, 1.2);
        start = start.AddRange(61, 80, 0.9);
        double[] values = new double[70];
        for (int i = 1; i < values.Length; i++)
            values[i] = start.GetValue(i);

        TreeNode array = TreeNode.MakeTreePart(
            new Tuple<int, int, double>[]
            {
                Tuple.Create(1, 10, 1.0),
                Tuple.Create(11, 35, 2.5),
                Tuple.Create(36, 49, 3.8),
                Tuple.Create(50, 60, 1.2),
                Tuple.Create(61, 80, 0.9)
            });

        for (int i = 1; i < values.Length; i++)
            values[i] = start.GetValue(i);
    }
公共抽象类树节点
{
公共静态双QuickAndDirty(整数索引)
{
双结果=1.0;
如果(索引>10)
结果=2.5;
如果(索引>35)
结果=3.8;
如果(索引>49)
结果=1.2;
如果(索引>60)
结果=0.9;
返回结果;
}
公共摘要双GetValue(int索引);
公共抽象树节点AddRange(int begin、int end、double value);
公共静态树节点MakeTreePart(元组[]范围)
{
返回TreeNode.MakeTreePart(范围,0,范围.长度>>1,范围.长度-1);
}
私有静态树节点MakeTreePart(元组[]范围,int-min,int-index,int-max)
{
如果(索引==最小值| |索引==最大值)
返回新叶(范围[index].Item1,范围[index].Item2,范围[index].Item3);
返回新的分段树(
范围[索引].Item2+.5,
生成树部件(范围,最小值,索引>>1,索引-1),

MakeTreePart(ranges,index+1,index=begin&&index我花了一些时间,但是我有一个QuickAndDirty方法,它假设所有给定的值都是有效的,并且范围是相邻的,而不使用任何数据结构。 以及一个非常特定的数据结构,它只会在给定的索引正好在指定范围内时返回某些内容,并且可以在运行时进行扩展

public abstract class TreeNode
{
    public static double QuickAndDirty(int index)
    {
        double result = 1.0;

        if (index > 10)
            result = 2.5;

        if (index > 35)
            result = 3.8;

        if (index > 49)
            result = 1.2;

        if (index > 60)
            result = 0.9;

        return result;
    }

    public abstract double GetValue(int index);

    public abstract TreeNode AddRange(int begin, int end, double value);

    public static TreeNode MakeTreePart(Tuple<int, int, double>[] ranges)
    {
        return TreeNode.MakeTreePart(ranges, 0, ranges.Length >> 1, ranges.Length - 1);
    }

    private static TreeNode MakeTreePart(Tuple<int, int, double>[] ranges, int min, int index, int max)
    {
        if (index == min || index == max)
            return new Leaf(ranges[index].Item1, ranges[index].Item2, ranges[index].Item3);

        return new SegmentTree(
            ranges[index].Item2 + .5,
            TreeNode.MakeTreePart(ranges, min, index >> 1, index - 1),
            TreeNode.MakeTreePart(ranges, index + 1, index << 1, max));
    }
}

public class SegmentTree : TreeNode
{
    private double pivot;
    private TreeNode left, right;

    public SegmentTree(double pivot, TreeNode left, TreeNode right)
    {
        this.pivot = pivot;
        this.left = left;
        this.right = right;
    }

    public override double GetValue(int index)
    {
        if (index < pivot)
            return left.GetValue(index);
        return right.GetValue(index);
    }

    public override TreeNode AddRange(int begin, int end, double value)
    {
        if (end < pivot)
            this.left = this.left.AddRange(begin, end, value);
        else
            this.right = this.right.AddRange(begin, end, value);
        // Do this to confirm to the interface.
        return this;
    }
}

public class Leaf : TreeNode
{
    private int begin, end;
    private double value;

    public Leaf(int begin, int end, double value)
    {
        this.begin = begin;
        this.end = end;
        this.value = value;
    }

    public override double GetValue(int index)
    {
        if (index >= begin && index <= end)
            return value;
        throw new Exception("index out of range");
    }

    public override TreeNode AddRange(int begin, int end, double value)
    {
        if (this.end < begin)
            return new SegmentTree(((double)this.end + begin) * .5, this, new Leaf(begin, end, value));
        else if (end < this.begin)
            return new SegmentTree(((double)end + this.begin) * .5, new Leaf(begin, end, value), this);
        else throw new Exception("Indexes overlap.");
    }
}
    static void Main()
    {
        TreeNode start = new Leaf(36, 49, 3.8);
        start = start.AddRange(11, 35, 2.5);
        start = start.AddRange(1, 10, 1.0);
        start = start.AddRange(50, 60, 1.2);
        start = start.AddRange(61, 80, 0.9);
        double[] values = new double[70];
        for (int i = 1; i < values.Length; i++)
            values[i] = start.GetValue(i);

        TreeNode array = TreeNode.MakeTreePart(
            new Tuple<int, int, double>[]
            {
                Tuple.Create(1, 10, 1.0),
                Tuple.Create(11, 35, 2.5),
                Tuple.Create(36, 49, 3.8),
                Tuple.Create(50, 60, 1.2),
                Tuple.Create(61, 80, 0.9)
            });

        for (int i = 1; i < values.Length; i++)
            values[i] = start.GetValue(i);
    }
公共抽象类树节点
{
公共静态双QuickAndDirty(整数索引)
{
双结果=1.0;
如果(索引>10)
结果=2.5;
如果(索引>35)
结果=3.8;
如果(索引>49)
结果=1.2;
如果(索引>60)
结果=0.9;
返回结果;
}
公共摘要双GetValue(int索引);
公共抽象树节点AddRange(int begin、int end、double value);
公共静态树节点MakeTreePart(元组[]范围)
{
返回TreeNode.MakeTreePart(范围,0,范围.长度>>1,范围.长度-1);
}
私有静态树节点MakeTreePart(元组[]范围,int-min,int-index,int-max)
{
如果(索引==最小值| |索引==最大值)
返回新叶(范围[index].Item1,范围[index].Item2,范围[index].Item3);
返回新的分段树(
范围[索引].Item2+.5,
生成树部件(范围,最小值,索引>>1,索引-1),
MakeTreePart(范围、索引+1、索引=开始和索引)查看或结构(可能后者更适合您的问题)查看或结构(可能后者更适合您的问题)