C#Crazy Foreach行为

时间:2017-04-27 12:50:09

标签: c#

我编写了一个从开放API获取数据的小程序。从这些对象生成对象,并将这些对象列表与数据库中的某些数据也在对象列表中进行比较

问题是每个循环完成时foreach循环越来越慢。

你会看到我不是专业人士。我还是初学者,我找不到解决方案。

这是一张会发生什么的图片:

enter image description here

非常感谢每一个提示。

这是我的代码:

public static List<Player> comparePlayersWithDB(Boolean difference, List<Player> jsonPlayer, List<Player> dBPlayer)
{
    List<Player> result = new List<Player>();

    if (!difference)
    {
        Console.WriteLine("Searching for new Players -- " + DateTime.Now.ToLocalTime());
    }
    else
    {
        Console.WriteLine("Searching for differences in Players -- " + DateTime.Now.ToLocalTime());
    }

    DateTime startTime = DateTime.Now;

    double statPercent = 0;
    var count = jsonPlayer.Count;
    int playerCount = 0;
    int lastPlayerCount = 0;
    double multiplier = ((double)100 / count);
    int nextStep = 10;
    Console.WriteLine("  0% ...... -- " + DateTime.Now.ToLocalTime());

    foreach (Player currentJson in jsonPlayer)
    {
        playerCount += 1;
        //Message to User
        if (statPercent >= nextStep)
        {
            int secondsGone = (DateTime.Now - startTime).Seconds;
            if (secondsGone == 0)
            {
                secondsGone += 1;
            }
            int playersEachSecons = (playerCount - lastPlayerCount) / secondsGone;
            Console.WriteLine(" " + (int)statPercent + "% (" + playerCount + "/" + count + ")......Speed: " + playersEachSecons + " Player/Second -- " + DateTime.Now.ToLocalTime());

            lastPlayerCount = playerCount;
            nextStep += 10;
            startTime = DateTime.Now;
        }


        if (dBPlayer.Exists(x => x.Name == currentJson.Name))
        {
            if (difference)
            {
                //Check for differences
                Player inDB = dBPlayer.Find(y => y.Name == currentJson.Name);
                if (inDB.XP != currentJson.XP || inDB.RP != currentJson.RP || inDB.Guild != currentJson.Guild)
                {
                    result.Add(currentJson);
                }
            }
        }
        // If currentPlayer not exists
        else
        {
            //and we are looking only for new Players
            if (!difference)
            {
                result.Add(currentJson);
            }
        }
        statPercent += multiplier;
    }
    return result;
}

2 个答案:

答案 0 :(得分:1)

尝试在dBPlayer之前foreach创建一个查找。

var playerLookup = dbPlayer.ToLookup(p => p.Name);

然后你可以做

if (playerLookup.Contains(currentJson.Name))
{
    if (difference)
    {
        //Check for differences
        Player inDB = playerLookup[currentJson.Name].First();
        if (inDB.XP != currentJson.XP || inDB.RP != currentJson.RP || inDB.Guild != currentJson.Guild)
        {
            result.Add(currentJson);
        }
    }
}

这比在Exists列表中执行Find然后dbPlayer执行速度更快。或者,如果您确定不会有任何重复的名称,则可以使用ToDictionary代替。

答案 1 :(得分:0)

当您调用Exists时,必须循环完整的dbPlayers列表(在最坏的情况下,没有匹配的条目)。然后,如果匹配,则调用dbPlayer.Find(),这基本上会再次完成整个事情。最好调用Find()并将结果保存在变量中。如果变量为null,则表示没有匹配项,否则您已经拥有了所请求的条目。

您仍有一个缺点,即您每次都有dbPlayer循环遍历所有值的风险,这会导致dbPlayer条目越多,性能越差。

我建议将dbPlayer列表转换为Dictionary,其中每个列表条目的Name成为字典的键,如下所示:

using System.Linq;
[...]
var dbPlayerDict = dbPlayer.ToDictionary(x => x.Name);

这将允许您通过调用TryGetValue()来查找现有玩家,无论需要搜索多少条目,它都具有相同的性能,使您的代码看起来像这样:

Player inDB;
if (dBPlayerDict.TryGetValue(currentJson.Name, out inDB))
{
    if (difference)
    {
        //Check for differences
        if (inDB.XP != currentJson.XP || inDB.RP != currentJson.RP || inDB.Guild != currentJson.Guild)
        {
            result.Add(currentJson);
        }
    }
}

如果多个玩家可以使用相同的名称,那么最好使用Lookup类,如@ juharr的回答中所述。