简体   繁体   English

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

[英]Checking against a changing set of integer ranges using C#

When filling in a form, the user needs to specify an amount. 填写表格时,用户需要指定一个数量。 This amount is then checked against approximately 4 to 6 ranges. 然后在大约4到6范围内检查此数量。 The selected range is then saved in the database. 然后将所选范围保存在数据库中。 The original amount will not be stored (for non-technical reasons) . 原始金额将不会存储(出于非技术原因) There will be no overlay between the ranges, eg: 范围之间将没有重叠,例如:

  • 0-999
  • 1000-1999
  • 2000-4999
  • 5000-9999
  • 10000-higher

The tricky part is that these ranges are not fixed in stone. 棘手的部分是这些范围不是一成不变的。 There can be alterations and additional ranges can be added to further specify the '10000 and higher' range. 可以进行更改,也可以添加其他范围以进一步指定“ 10000及更高”范围。 These changes will occur a couple of times and can't be prevented. 这些更改将发生两次,并且无法避免。 The old ranges will need to be stored since the specific amount can not be saved to the database. 由于无法将特定数量保存到数据库,因此需要存储旧范围。

What would be the most efficient C# data structure for checking against a changing set of ranges? 对于一组变化的范围,最有效的C#数据结构是什么?

For my research I included: 对于我的研究,我包括:

  • One of the answers here suggest that a fixed set of integer ranges in a switch statement is possible with C#7. 此处的答案之一表明,使用C#7,可以在switch语句中使用一组固定的整数范围。 However, it is not possible to dynamically add cases to and/or remove cases from a switch statement. 但是,不可能向switch语句动态添加案例和/或从switch语句删除案例。

  • This question suggests that using Enumerable.Range is not the most efficient way. 这个问题表明使用Enumerable.Range不是最有效的方法。

A simple approach here is to store the lower band values in an array, and pass it to a FindBand() method which returns an integer representing the index of the band containing the value. 这里的一种简单方法是将较低频段的值存储在数组中,并将其传递给FindBand()方法,该方法返回一个整数,该整数表示包含该值的频段的索引。

For example: 例如:

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;
}

Test code: 测试代码:

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));

This isn't the fastest approach if there are a LOT of bands, but if there are just a few bands this is likely to be sufficiently fast. 如果有很多频段,这不是最快的方法,但是如果只有几个频段,这可能足够快。

(If there were a lot of bands, you could use a binary search to find the appropriate band, but that would be overkill for this in my opinion.) (如果有很多乐队,您可以使用二进制搜索来找到合适的乐队,但是在我看来,这太过分了。)

You can sort low bounds , eg 您可以对下限进行排序,例如

// 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)
};

and then find the correct group ( 0-based ) 然后找到正确的组(从0开始

   int index = Array.BinarySearch(lowBounds, value);

   index = index < 0 ? index = -index - 1 : index + 1;

Demo: 演示:

  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));

Outcome: 结果:

   -10 : 0
     0 : 1
    45 : 1
   999 : 1
  1000 : 2
  1997 : 2
  5123 : 4
 10000 : 5
 20000 : 5

Since there are already great answers regarding how to find the correct range, I'd like to address the persistence issue. 既然已经有关于如何找到正确范围的好答案,我想解决持久性问题。

What do we have here? 我们有什么在这里?

  1. You cannot persist the exact value. 您不能保留确切的值。 ( Not allowed ) ( 不允许 )
  2. Values will be "blurred" by fitting them into a range. 值将通过使它们适合范围而被“模糊”。
  3. Those ranges can (and will) change over time in bounds and number. 这些范围可以(并且将)随着时间的推移在范围和数量上变化。

So, what I would probably do would be to persist lower and upper bound explicitly in the db. 因此,我可能要做的是在数据库中明确地保持上限和下限 That way, if ranges change, old data is still correct. 这样,如果范围更改,则旧数据仍然正确。 You cannot "transform" to the new ranges, because you cannot know if it would be correct. 您无法“转换”为新范围,因为您不知道它是否正确。 So you need to keep the old values. 因此,您需要保留旧的值。 Any new entries after the change will reflect the new ranges. 更改后的任何新条目将反映新范围。

One could think of normalization, but honestly, I think that would be overcomplicating the problem. 可以想到标准化,但老实说,我认为这会使问题变得更加复杂。 I'd only consider that if the benefit (less storage space) would greatly outweigh the complexity issues. 我只会考虑如果好处(更少的存储空间)将大大超过复杂性问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM