C# 使用C检查一组不断变化的整数范围#

C# 使用C检查一组不断变化的整数范围#,c#,integer,range,C#,Integer,Range,填写表单时,用户需要指定金额。然后对照大约4到6个范围检查该金额。然后将选定的范围保存在数据库中。不会存储原始金额(出于非技术原因)。范围之间不会有重叠,例如: 0-999 1000-1999 2000-4999 5000-9999 10000以上 棘手的是,这些范围不是固定不变的。可以进行更改,也可以添加其他范围,以进一步指定“10000及以上”范围。这些变化会发生几次,无法阻止。由于无法将具体金额保存到数据库中,因此需要存储旧范围 对于检查不断变化的范围集,最有效的C#数据结构是什么 我

填写表单时,用户需要指定金额。然后对照大约4到6个范围检查该金额。然后将选定的范围保存在数据库中。不会存储原始金额(出于非技术原因)。范围之间不会有重叠,例如:

  • 0-999
  • 1000-1999
  • 2000-4999
  • 5000-9999
  • 10000以上
棘手的是,这些范围不是固定不变的。可以进行更改,也可以添加其他范围,以进一步指定“10000及以上”范围。这些变化会发生几次,无法阻止。由于无法将具体金额保存到数据库中,因此需要存储旧范围

对于检查不断变化的范围集,最有效的C#数据结构是什么

我的研究包括:

  • 建议使用C#7可以在switch语句中使用一组固定的整数范围。但是,不可能在switch语句中动态添加案例和/或从中删除案例

  • 建议使用Enumerable.Range不是最有效的方法


这里的一种简单方法是将较低的频带值存储在数组中,并将其传递给
FindBand()
方法,该方法返回一个整数,表示包含该值的频带的索引

例如:

public static int FindBand(double value, double[] bandLowerValues)
{
    for (int i = 0; i < bandLowerValues.Length; ++i)
        if (value < bandLowerValues[i])
            return Math.Max(0, i-1);

    return bandLowerValues.Length;
}
如果有很多波段,这不是最快的方法,但是如果只有几个波段,这可能足够快

(如果有很多条带,你可以使用二进制搜索来找到合适的条带,但我认为这样做太过分了。)

你可以对下限排序,例如

然后找到正确的组(基于0)


由于关于如何找到正确的范围已经有了很好的答案,我想解决持久性问题

我们这里有什么

  • 您不能保留确切的值。(不允许)
  • 通过将值拟合到一个范围,值将“模糊”
  • 这些范围可以(也将)随着时间的推移在范围和数量上发生变化
  • 因此,我可能会做的是在db中显式地保持上下限。 这样,如果范围改变,旧数据仍然正确。您无法“转换”到新范围,因为您无法知道它是否正确。因此,您需要保留旧的值。更改后的任何新条目都将反映新的范围


    人们可以考虑正常化,但老实说,我认为这会使问题变得过于复杂。我只想,如果好处(更少的存储空间)将大大超过复杂性问题。

    显然,开关不会为你工作。你还可以做些什么,你的第二个问题是指出一种方法,将范围存储在内存中,并遍历它们。无论是数组、列表还是IEnumerable。。扫描任何东西中的5个元素都不会对性能造成巨大影响,除非这是超性能的关键任务。请注意,在C#8中会有一个内置的
    范围
    类型(我不知道它是否对您有帮助)。您在这里混合了几个问题。1.如何以DB保存“范围”?2.如何处理对范围的更改?这些需要单独处理。由于您无法保存原始工资(我猜是这样的,对吧?),因此在保留范围时会丢失信息。示例:“2031.49”=>“2k-4.999”。现在,如果该范围更改为“1.5k-4.5k”,则旧信息将无效,因为您无法判断初始值是否仍在该范围内。所以,如果你想保持一致,就需要引入“历史”数据。@Fildor我正在研究一种方法来保存数据库中的范围。我尽量只回答一个问题。1.000是1000分隔符,我将在我的问题中更改它。
    双倍值
    -我很有信心我们正在处理货币金额。因此,我建议不要使用
    double
    ,尽管在这种情况下可能没有什么区别。是的,使用
    decimal
    类型作为货币,但OP的代码没有为浮点数指定
    m
    后缀,因此它们是
    double
    。同意,我只是想提出这个建议,因为我曾经在从一个重构到另一个重构时遇到很多麻烦。因此,我想省去其他人的麻烦。我决定将所选范围与数据库中可能的范围一起保存为JSON字符串,例如
    {“ranges”:[10002000500010000],“SelectedRange”:0}
    。索引0将转换为范围0-999,索引1将生成1000-2000,以此类推。这样,当选择新范围时,旧数据不会丢失。
    double[] bandLowerValues = {0, 1, 2, 5, 10};
    
    Console.WriteLine(FindBand(-1, bandLowerValues));
    Console.WriteLine(FindBand(0, bandLowerValues));
    Console.WriteLine(FindBand(0.5, bandLowerValues));
    Console.WriteLine(FindBand(1, bandLowerValues));
    Console.WriteLine(FindBand(1.5, bandLowerValues));
    Console.WriteLine(FindBand(2.5, bandLowerValues));
    Console.WriteLine(FindBand(5, bandLowerValues));
    Console.WriteLine(FindBand(8, bandLowerValues));
    Console.WriteLine(FindBand(9.9, bandLowerValues));
    Console.WriteLine(FindBand(10, bandLowerValues));
    Console.WriteLine(FindBand(11, bandLowerValues));
    
    // or decimal instead of double if values are money
    double[] lowBounds = new double[] {
          0, // 0th group:  (-Inf ..     0)
       1000, // 1st group:     [0 ..  1000)
       2000, // 2nd group:  [1000 ..  2000)
       5000, // 3d  group:  [2000 ..  5000)
      10000, // 4th group:  [5000 .. 10000)
             // 5th group: [10000 ..  +Inf)
    };
    
       int index = Array.BinarySearch(lowBounds, value);
    
       index = index < 0 ? index = -index - 1 : index + 1;
    
      double[] tests = new double[] {
          -10,
            0,
           45,
          999,
         1000,
         1997,
         5123,
        10000,
        20000,
      };
    
      var result = tests
        .Select(value => {
          int index = Array.BinarySearch(lowBounds, value);
    
          index = index < 0 ? index = -index - 1 : index + 1;
    
          return $"{value,6} : {index}";
        });
    
      Console.Write(string.Join(Environment.NewLine, result));
    
       -10 : 0
         0 : 1
        45 : 1
       999 : 1
      1000 : 2
      1997 : 2
      5123 : 4
     10000 : 5
     20000 : 5