Как создать последовательность чисел при соблюдении некоторых ограничений?

используйте «\ p {Pd}» без кавычек, чтобы соответствовать любому типу дефиса. Символ «-» - это всего лишь один тип дефиса, который также является особым символом в Regex.

6
задан marc_s 2 April 2019 в 18:07
поделиться

2 ответа

Используя идею, опубликованную ckuri , и включая улучшения, предложенные Эриком Липпертом , вы можете сгруппировать список чисел по суффиксу:

var prefixLength = 100;
var suffixLength = 10000;

 Enumerable
  .Range(0, prefixLength * suffixLength)
  .OrderBy(number => rnd.Next())
  .GroupBy(number => number % suffixLength)

Тогда , вы можете сгладить список:

Enumerable
 .Range(0, prefixLength * suffixLength)
 .OrderBy(number => rnd.Next())
 .GroupBy(number => number % suffixLength)
 .SelectMany(g => g)

До этого момента у вас будет список чисел, где в каждых 100 строках (prefixLength) префиксы будут одинаковыми. Таким образом, вы можете выбрать их, получив индекс каждой строки:

Enumerable
 .Range(0, prefixLength * suffixLength)
 .OrderBy(number => rnd.Next())
 .GroupBy(number => number % suffixLength)
 .SelectMany(g => g)
 .Select((g, index) => new { Index = index, Number = g })

Используя информацию об индексе, вы можете сгруппировать строки, применяя функцию мода, используя prefixLength как фактор:

[113 ]

Наконец, вы можете снова сгладить список и преобразовать значения в строку, чтобы получить окончательный результат:

Enumerable
 .Range(0, prefixLength * suffixLength)
 .OrderBy(number => rnd.Next())
 .GroupBy(number => number % suffixLength)
 .SelectMany(g => g)
 .Select((g, index) => new { Index = index, Number = g })
 .GroupBy(g => g.Index % prefixLength, g => g.Number)
 .SelectMany(g => g)
 .Select(number => $"{number/suffixLength:d2}{number%suffixLength:d4}")
0
ответ дан Rodolfo Santos 2 April 2019 в 18:07
поделиться

[Я переписал ранее, неправильное решение, основанное на неправильном понимании проблемы].


Мы начнем с создания вспомогательного метода, который создает перетасованный диапазон на основе заданного начального числа:

static IEnumerable<int> ShuffledRange(int size, int seed)
{
  var rnd = new Random(seed);
  return Enumerable.Range(0, size).OrderBy(p => rnd.Next());
}

Следующее, что мы собираемся сделать, - это рандомизировать все суффиксы и получить все они в последовательности. Обратите внимание, что для каждого шаффла мы используем разные начальные числа, но их значение предсказуемо.

static IEnumerable<string> ShuffledIds(int seed)
{
  const int s = 10000;
  const int p = 100;
  var suffixes = Enumerable.Range(0, p)
    .Select(seedOffset => ShuffledRange(s, seed + seedOffset)
    .SelectMany(x => x);

Мы встретили ограничение, что каждый кусок 10000 имеет все 10000 суффиксов в случайном порядке. Теперь мы должны распределить 10000 каждого префикса. Давайте сделаем последовательность префиксов для каждого возможного суффикса. (Опять же, мы используем еще не использованное начальное число для каждого перемешивания.)

  var dict = new Dictionary<int, IEnumerator<int>>();
  for (int suffix = 0; suffix < s; suffix += 1)
    dict[suffix] = ShuffledRange(p, seed + p + suffix).GetEnumerator();

И теперь мы можем распределить их

  foreach(int suffix in suffixes)
  {
    dict[suffix].MoveNext();
    yield return dict[suffix].Current.ToString("d2") +
     suffix.ToString("d4");
  }
}

И это должно быть сделано.

Обратите внимание, что это также имеет приятное свойство: алгоритм перестановки больше не относится к коду, который нуждается в перестановках. Попробуйте инкапсулировать такие детали в вспомогательные функции.

0
ответ дан Eric Lippert 2 April 2019 в 18:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: