Могу ли я быстрее находить выигрыши и ничьи

#c# #optimization

Вопрос:

У меня есть приложение, учитывающее время, в котором я получаю ранг каждого объекта и определяю, кто выиграл или сыграл вничью первым. С моим текущим алгоритмом я получаю некоторое отставание в своей программе, поэтому надеюсь ускорить ее. В этой демо-версии я просто получаю случайное число для рангов, так как для расчета реального ранга требуется слишком много кода для публикации.

Кто-нибудь может подсказать, как я мог бы сделать это быстрее, так как метод обновления может вызываться десятки тысяч раз за один запуск?

 class Program
{
    static int runOuts = 0;
    static Dictionary<RankedObject, int> dictionaryWins = new Dictionary<RankedObject, int>();
    static Dictionary<RankedObject, int> dictionaryDraws = new Dictionary<RankedObject, int>();
    static Random random = new Random();
    static List<RankedObject> rankedObjects = new List<RankedObject>();

    static void Main(string[] args)
    {
        // create some objects for demo
        rankedObjects.Add(new RankedObject());
        rankedObjects.Add(new RankedObject());
        rankedObjects.Add(new RankedObject());

        // add each object to the win/draw dictionaries so we can count wins/draws for each
        foreach (RankedObject rankedObj in rankedObjects)
        {
            dictionaryWins.Add(rankedObj, 0);
            dictionaryDraws.Add(rankedObj, 0);
        }

        // calculate wins/draws many times
        for (int i = 0; i < 10000; i  )
        {
            Update();
        }
        

        // set equity results in each ranked combo and print results
        foreach (RankedObject rankedCombo in rankedObjects)
        {
            rankedCombo.WinEquity = dictionaryWins[rankedCombo] / (double)runOuts;
            rankedCombo.DrawEquity = dictionaryDraws[rankedCombo] / (double)runOuts;
            Console.WriteLine(rankedCombo);
        }
    }

    private static void Update()
    {
        // keep a list of ranks for each object so we can get max/winning value easily
        List<int> ranks = new List<int>();

        // get a rank for each object
        foreach (RankedObject rankedCombo in rankedObjects)
        {
            int rank = random.Next(3);
            ranks.Add(rank);
            rankedCombo.Rank = rank;
        }

        // get the maximum rank and how many times it occurs, so we know if their is a tie for the win
        int max = ranks.Max();
        int maxOccurences = 0;
        foreach (int i in ranks)
        {
            if (i == max)
            {
                maxOccurences  ;
            }
        }

        // loop over each object to record if the object won or tied for win
        foreach (RankedObject rankedObj in rankedObjects)
        {
            if (rankedObj.Rank == max amp;amp; maxOccurences == 1) // current rankedObj was winner
            {
                dictionaryWins[rankedObj]  = 1;

            }
            else if (rankedObj.Rank == max amp;amp; maxOccurences > 1) // current rankedObj Tied for win
            {
                dictionaryDraws[rankedObj]  = 1;

            }
        }
        runOuts  ;
    }
}


class RankedObject
{
    int rank;
    double winEquity;
    double drawEquity;

    public int Rank { get => rank; set => rank = value; }
    public double WinEquity { get => winEquity; set => winEquity = value; }
    public double DrawEquity { get => drawEquity; set => drawEquity = value; }

    public override string ToString()
    {
        return "Win Equity: "   winEquity   ", Draw Equity: "   drawEquity;
    }
}
 

Комментарии:

1. циклы foreach работают намного медленнее, чем для циклов codingsight.com/foreach-or-for-that-is-the-question поэтому я бы начал с замены этих

2. Вам не нужен массив для определения максимального значения и подсчета количества его повторений.

3. Может быть, этот вопрос лучше подходит для codereview.stackexchange.com

4. Первый шаг в оптимизации: измерение и профиль. Сколько времени занимает код? И где же тратится это время?

5. В вашем списке вам не нужно сохранять все ранжированные объекты, которые вы ранее просматривали. Вместо этого храните только несколько ранжированных объектов, которые являются текущими максимальными. Когда вы найдете новый максимальный ранг, очистите список и снова добавьте новый максимальный объект.