有效的方法来配对来自两个独立集合的有限数量的随机元素

时间:2015-10-29 14:04:38

标签: c#

我有两个列表(lista和listb),每个列表包含一个未知数量的点(结构中有两个整数)。

我想创建一个包含lista和listb中唯一随机配对的新列表。所以一个示例条目可能是[12,14],其中12是lista的索引,14是listb的索引。

我还想在调用此函数时设置最大配对数。因此,不是将lista中的每个元素与listb中的每个元素配对,而是将其限制为200个随机配对作为示例。

我的第一次尝试是简单地生成所有可能的配对。随机播放列表并将任何元素都删掉。这个解决方案几乎没有足够的效率。

我的下一个尝试是为每个可能索引的每个原始列表创建一个数组,将它们分开进行洗牌,然后迭代它们直到我有最大数量的配对(或所有这些配对)。这有几个问题,我不确定如何解决。其中之一,lista可以拥有1000万个元素供我所知。创建一个包含1000万个元素的新数组(索引列表)并在我的最大对可能只有200时进行混洗?到目前为止似乎很傻。

我考虑过从lista / listb中选择随机元素,看看我是否已经将它们配对,然后再将它们添加到新列表中。这也是一个非常愚蠢的选择,因为可以花很多时间一遍又一遍地选择重复配对。

那么,这里有什么好选择还是有选择呢?我不想迭代每个可能的组合,配对需要是唯一的,从列表中删除选项是非常慢的,因为当它们非常大时阵列重新调整大小,在选择中分布需要非常均匀每个清单的过程等。

感谢您的帮助。

编辑 - 我的意思是关于对子本身的独特方面。因此,只要listb中的元素每次都不同,lista中的元素10就可以反复使用。唯一的问题是我不想立即限制lista和listb,因为我需要在每个配对的两个列表中进行相当均匀的分配。

2 个答案:

答案 0 :(得分:1)

数学或统计数据buff可能会为您提供一个评估此公式的公式,但我只是编写了一些测试代码。

代码只是选择随机对,每次看到重复时它都会再次尝试。然后对于每个这样的“选择随机对直到唯一”循环,它计算它做了多少重试并跟踪它。最后,这总结为一个全局数组来跟踪这些事物的相对频率。

这是执行约1分钟后的结果:

84382319 81 0 0 0 0 0 0 0 0

这些数字意味着:

  • 421912个周期[(84382319 + 81)/ 200]:
    • 找到81个重复项但重试没有找到重复项(第3个数字,最多为0个)
    • 84382319在第一次尝试时可以找到唯一的对,没有重复

所以,显然如果你增加你想要产生的对数或者减少选择错误的数字,这将开始上升,但我不确定这会在实践中造成问题。

这是我使用的LINQPad程序:

static Random R = new Random();
void Main()
{
    var a = 10000;
    var b = 10000;
    var n = 200;

    int[] counts = new int[10];
    var dc = new DumpContainer().Dump();

    while (true)
    {
        var once = Test(a, b, n);
        for (int i = 0; i < once.Length; i++)
            counts[i] += once[i];
        dc.Content = Util.HorizontalRun(true, counts);
    }
}

public static int[] Test(int a, int b, int n)
{
    var seen = new HashSet<Tuple<int, int>>();
    var result = new int[10];

    for (int index = 0; index < n; index++)
    {
        int tries = 0;
        while (true)
        {
            var av = R.Next(a);
            var bv = R.Next(a);
            var t = Tuple.Create(av, bv);
            if (seen.Contains(t))
                tries++;
            else
            {
                seen.Add(t);
                break;
            }
        }
        result[tries]++;
    }
    return result;
}

答案 1 :(得分:1)

为避免完全重复,您可以尝试执行稀疏 Fisher-Yates shuffle

  • 创建一个Dictionary<int, int> dict,它将映射Fisher-Yates数组中没有自己索引的&#34;索引&#34;到&#34;该指数的值&#34;。
  • 对于n项,请从x(包括)中选择一个随机数n到&#34; ListA的大小&ListB的大小&#34; (独家)
    • dict[x] ?? x是您的所选项目
    • dict[n] ?? n存储在dict[x]
    • 选定的项目映射回一对索引(除以ListB索引的ListA大小,按ListA索引的ListA大小除以模数)。