如何设置 IEnumerable 的大小? C#

How does the size of IEnumerable get set? C#

我有一些代码不是我自己写的,我正试图用它来构建一个 Poker ICM 计算器程序。该程序采用一系列筹码量​​和奖金支出,并计算每个玩家的奖金净值。 该代码适用于 3 个奖项,但是当我添加第 4 个奖项时,我得到一个索引越界错误,因为当对象仅包含索引 0 到 2 时我试图获得排列 [3]。问题是我无法理解排列的大小是如何设置的,所以我不知道如何调整代码来获得更多的奖品。我会很感激一些帮助。 下面是一个最小的工作示例,其中包含主要方法中的工作代码和非工作代码以及指示错误发生位置的注释。

ICMCalculator.cs

    class ICMCalculator
    {
        public double[] CalcEV(int[] structure, int[] chips)
        {
            //the probability of a players position
            double[,] probabilitys = new double[structure.Length, chips.Length];
            //the expected value of the player
            double[] EVs = new double[chips.Length];
            int[] players = new int[chips.Length];


            for (int i = 0; i < players.Length; ++i)
                    players[i] = i;
                IEnumerable<int[]> permutations;
    
                for (int i = 0; i < structure.Length; ++i)
                {
                    permutations = (new Permutation()).Enumerate(players, i + 2);
                    foreach (int[] permutation in permutations)
                    {
                       // OUT OF BOUNDS ERROR OCCURS HERE
                        probabilitys[i, permutation[i]] += CalcPermutationProbability(permutation, chips);
                    }
                }
    
            for (int i = 0; i < structure.Length; ++i)
            {
                for (int j = 0; j < chips.Length; ++j)
                    EVs[j] += probabilitys[i, j] * structure[i];
            }
            return EVs;
        }

        private double CalcPermutationProbability(int[] permutations, int[] chips)
        {
            double probability = 1.0F;
            int chips_sum = chips.Sum();

            for (int i = 0; i < permutations.Length; ++i)
            {
                probability *= System.Convert.ToDouble(chips[permutations[i]]) / System.Convert.ToDouble(chips_sum);
                chips_sum -= chips[permutations[i]];
            }
            return probability;
        }
    }

Permutation.cs

class Permutation
{
   public IEnumerable<T[]> Enumerate<T>(IEnumerable<T> nums, int length)
    {
        var perms = _GetPermutations<T>(new List<T>(), nums.ToList(), length);
        return perms;
    }

    private IEnumerable<T[]> _GetPermutations<T>(IEnumerable<T> perm, IEnumerable<T> nums, int length)
    {
        if (length - perm.Count() <= 0)
        {
            yield return perm.ToArray();
        }
        else
        {
            foreach (var n in nums)
            {
                var result = _GetPermutations<T>(perm.Concat(new T[] { n }),
                    nums.Where(x => x.Equals(n) == false), length - perm.Count());

                foreach (var xs in result)
                    yield return xs.ToArray();
            }
        }
    }
}

Utils.cs

class Utils
{
    public static string DoubleArrayToString(double[] doubles)
    {
        StringBuilder sb = new StringBuilder();
        foreach (double dub in doubles)
        {
            sb.AppendLine(Utils.Format2DP(dub));
        }
        return sb.ToString().Trim();
    }

}

Program.cs

static class Program
{
    static void Main()
    {
        // THIS WORKS
        ICMCalculator ev = new ICMCalculator();
        int[] stacks = new int[] { 4500, 2700, 1800, 1000, 500 };
        int[] prizes = new int[] { 84,36,18 }; 
        int prizePool = prizes.Sum();
        double[] equity = ev.CalcEV(prizes, stacks);
        Console.WriteLine(Utils.DoubleArrayToString(equity));

        // THIS THROWS INDEX ERROR
        ev = new ICMCalculator();
        stacks = new int[] { 4500, 2700, 1800, 1000, 500 };
        prizes = new int[] { 84,36,18,9 }; 
        prizePool = prizes.Sum();
        equity = ev.CalcEV(prizes, stacks);
        Console.WriteLine(Utils.DoubleArrayToString(equity));
    }
}

说清楚,我认为每个'permutation'应该是structure.Length的长度。我不想通过减小 i 的最大值来避免越界错误。我想我需要增加每个排列的大小以匹配 structure.Length 但我不知道该怎么做。

如果正确解析,当前失败的代码应该输出值:50.82、37.85、29.16、19.01、10.15

我认为问题出在这一行:

                var result = _GetPermutations<T>(perm.Concat(new T[] { n }),
                    nums.Where(x => x.Equals(n) == false), length - perm.Count());

相反,我认为应该是

                var result = _GetPermutations<T>(perm.Concat(new T[] { n }),
                    nums.Where(x => x.Equals(n) == false), length);

这里的问题是,当我们决定是否停止进一步递归时,我们重复计算了到目前为止找到的排列的长度。

条件length - perm.Count() <= 0(可以简化为perm.Count() >= length)用于停止对_GetPermutations的进一步调用,前提是目前生成的排列perm足够长被退回。这依赖于参数 length 作为结果排列所需的长度。但是,通过在对 _GetPermutations() 的递归调用中传递 length - perm.Count(),我们将减少对 _GetPermutations() 的内部调用接收到的 length 的值,从而导致它们提前停止递归排列太短。