Проверка на изменение набора целочисленных диапазонов с использованием C # - PullRequest
0 голосов
/ 22 января 2019

При заполнении формы пользователю необходимо указать сумму.Затем это количество проверяется на соответствие примерно 4-6 диапазонам.Выбранный диапазон затем сохраняется в базе данных. Первоначальная сумма не будет сохранена (по нетехническим причинам) .Между диапазонами не будет наложения, например:

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

Хитрость в том, что эти диапазоны не зафиксированы в камне.Могут быть изменения, и могут быть добавлены дополнительные диапазоны для дальнейшего определения диапазона «10000 и выше».Эти изменения произойдут пару раз и не могут быть предотвращены.Старые диапазоны необходимо будет сохранить, поскольку конкретное количество не может быть сохранено в базе данных.

Какая структура данных C # была бы наиболее эффективной для проверки по изменяющемуся набору диапазонов?

Для моего исследования я включил:

  • Один из ответов здесь предполагает, что с помощью C # 7 возможен фиксированный набор целочисленных диапазонов в выражении switch.Однако невозможно динамически добавлять наблюдения и / или удалять их из оператора switch.

  • Этот вопрос предполагает, что использование Enumerable.Range - не самый эффективный способ.

Ответы [ 3 ]

0 голосов
/ 22 января 2019

Вы можете отсортировать нижние границы , например,

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

, а затем найти правильную группу ( 0 на основе )

   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
0 голосов
/ 22 января 2019

Поскольку уже есть отличные ответы о том, как найти правильный диапазон, я бы хотел решить проблему с постоянством.

Что у нас здесь?

  1. Вы не можетесохранить точное значение.(Недопустимо)
  2. Значения будут «размыты», если поместить их в диапазон.
  3. Эти диапазоны могут (и будут) изменяться с течением времени в границах и числах.

Итак, я бы, вероятно, сделал бы, чтобы сохранил нижнюю и верхнюю границы явно в БД.Таким образом, если диапазоны изменяются, старые данные остаются верными.Вы не можете «преобразоваться» в новые диапазоны, потому что вы не можете знать, будет ли это правильно.Так что вам нужно сохранить старые ценности.Любые новые записи после изменения будут отражать новые диапазоны.

Можно подумать о нормализации, но, честно говоря, я думаю, что это усложнит проблему.Я бы только учел это, если бы выгода (меньше места для хранения) значительно перевесила бы сложности.

0 голосов
/ 22 января 2019

Простой подход заключается в том, чтобы сохранить значения нижней полосы в массиве и передать его методу 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;
}

Тестовый код:

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

Это не самый быстрый подход, если есть много полос, но если есть только несколько полос, этого, вероятно, будет достаточнобыстро.

(Если бы было много полос, вы могли бы использовать бинарный поиск, чтобы найти подходящую полосу, но, на мой взгляд, это было бы излишним).

...