c# - 如何在遵守某些约束的同时生成数字序列?

标签 c# algorithm linq combinatorics

我需要生成从 0 到 999999(不重复)的所有可能数字(整数),同时遵守一系列约束。

为了更好地理解要求,假设每个数字都由一个 2 位前缀和一个 4 位后缀组成。就像 000000 被读作 00-0000 和 999999 被读作 99-9999。现在是规则:

  • 前缀必须是随机的
  • 后缀必须随机排列,同时确保序列中的每 10k 个数字都包含从 0000 到 9999 的所有数字。
  • 必须能够在给定种子的情况下以相同的顺序再次生成数字。
  • 不是真正的要求,但如果使用 Linq 完成就更好了。

到目前为止,我已经编写了一些满足除第一个要求之外的所有要求的代码:

var seed = 102111;
var rnd = new Random(seed);
var prefix = Enumerable.Range(0, 100).OrderBy(p => rnd.Next());
var suffix = Enumerable.Range(0, 10000).OrderBy(s => rnd.Next());
var result = from p in prefix
                from s in suffix
                select p.ToString("d2") + s.ToString("d4");

foreach(var entry in result)
{
    Console.WriteLine(entry);
}

使用这个我可以使用相同的种子重现序列,前 10000 个数字的所有数字都从 0000 到 9999,第二个 10k 等等,但前缀并不是真正随机的,因为每个 10k 组将具有相同的前缀。

我还考虑过用数字和它的组(100 个组,每个组有 10k 个数字)创建一个类,以便更容易洗牌,但我相信这是更好、更简单的方法。

最佳答案

[基于对问题的误解,我覆盖了之前的错误解决方案]。


我们首先制作一个辅助方法,该方法根据给定的种子生成随机范围:

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 的每个 block 都具有所有 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");
  }
}

那应该就可以了。

请注意,这还有一个很好的特性,即洗牌算法不再是需要洗牌的代码的关注点。尝试将此类细节封装在辅助函数中。

关于c# - 如何在遵守某些约束的同时生成数字序列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55227755/

相关文章:

algorithm - 分析序列的算法

c - 如何找到任何整数的下一个 10 的倍数?

c# - Linq 结果以不同的顺序显示

c# - 如何检查SQL数据库中是否有记录?

c# - 在自定义中间件中测试 response.WriteAsync()

c# - 将 html 表转换为等宽字体纯文本表?

c++ - Gale Shapley 算法的实现有问题

c# - DISTINCT() 和 ORDERBY 问题

c# - 如果我的导航属性是单个项目,我如何在 linq 语句中使用 Expression<Func<T>>?

c# - 衡量方法的哪一部分花费大量时间的最佳实践?