3
  List<string> allApps = new List<string>();
        roster = MURLEngine.GetUserFriendDetails(token, userId);
        var usersfriends = from elements in roster.RosterEntries
                           where elements[0] == 'm' && elements[1] >= '0' && elements[1] <= '9'
                           select elements;
        foreach (string userid in usersfriends)
        {
            roster = MURLEngine.GetUserFriendDetails(token, userid);
            var usersapps = from elements in roster.RosterEntries
                            where elements[0] != 'm'
                            select elements;
            allApps.AddRange(usersapps);

            allApps = allApps.Distinct().ToList();
        }



        int countapps = 0;
        List<string> Appname = new List<string>();
        countapps = appList.Count();

        for (int y = 0; y < countapps; y++)
        {
            foreach (string li in allApps)  // 
            {
                bool istrueapp = appList.ElementAt(y).AppName.Equals(li);
                if (istrueapp == true)
                {
                    Appname.Add(appList.ElementAt(y).AppName);
                }
            }
        }

在上面的代码中,我首先得到一个字符串列表,即 usersfriends,然后基于这些 id,我得到用户的应用程序列表,然后将所有用户的所有应用程序添加到另一个列表,即 allApps,因此整个过程很慢使用列表执行此操作大约需要 20 秒。也尝试使用 HashSet 和 SortedSet 但它更慢。

我的问题是我应该在这种情况下使用什么数据结构?

真的会帮助我

4

4 回答 4

3

关于 LINQ,我最喜欢的一点是它可以让您描述您想要做什么,而不是让您编写一堆模糊目标的循环。这是您的代码的重构版本,我认为它非常清楚,并且在我的测试平台中运行得更快(0.5s vs ~15s)。

// create a hashset for fast confirmation of app names
var realAppNames = new HashSet<string>(appList.Select(a => a.AppName));

var roster = MURLEngine.GetUserFriendDetails(token, userId);

// get the ids of all friends
var friendIds = roster.RosterEntries
                      .Where (e => e[0] == 'm' && e[1] >= '0' && e[1] <= '9');

var apps = 
    friendIds 
    // get the rosters for all friends
    .SelectMany (friendId => MURLEngine.GetUserFriendDetails(token, friendId)).RosterEntries)
    // include the original user's roster so we get their apps too
    .Concat(roster.RosterEntries) 
    // filter down to apps only
    .Where (name => name[0] != 'm' && realAppNames.Contains(name)) 
    // remove duplicates
    .Distinct()
    // we're done!
    .ToList();
于 2013-09-28T17:36:51.850 回答
1

好的,到目前为止我能建议什么。

首先:你有很多Add'。
一般来说,默认List<T>不是很多Add's 的最佳数据结构,因为在内部它被实现为数组,当它满时被销毁并复制到更大的数组。
有两个选项:
- 创建具有预定义容量的列表:List<string> allApps = new List<string>(countOfApps);。如果您可以预先粗略计算要添加到列表中的项目的数量,那么这个很好。
- 使用LinkedList<string> allApps = new LinkedList<string>()。LinkedList 添加新项目的速度非常快。

同样的东西也适用于List<string> Appname = new List<string>();列表。

其次:一开始你有一个列表,它是distinct-ed,然后在foreach-loop的每次迭代中转换为列表,而新构建的列表不在该循环中使用。所以在这里你可以把distinct->tolist代码移出循环,代码逻辑不会改变,但性能会提高。

到目前为止,我可以建议以下代码:

 LinkedList<string> allApps2 = new LinkedList<string>();// linkedlist here
        roster = MURLEngine.GetUserFriendDetails(token, userId);
        var usersfriends = from elements in roster.RosterEntries
                           where elements[0] == 'm' && elements[1] >= '0' && elements[1] <= '9'
                           select elements;
        foreach (string userid in usersfriends)
        {
            roster = MURLEngine.GetUserFriendDetails(token, userid);
            var usersapps = from elements in roster.RosterEntries
                            where elements[0] != 'm'
                            select elements;
            foreach(var userapp in usersapps)// add _all the apps_ to list. Will be distinct-ed later
            {
                allApps2.AddLast(userapp);// don't worry, it works for O(1)
            }

        }

        var allApps = allApps2.Distinct().ToList();

        int countapps = 0;
        LinkedList<string> Appname2 = new LinkedList<string>();// linkedlist here
        countapps = appList.Count();

        for (int y = 0; y < countapps; y++)
        {
            foreach (string li in allApps)  // 
            {
                bool istrueapp = appList.ElementAt(y).AppName.Equals(li);
                if (istrueapp == true)
                {
                    Appname2.AddLast(appList.ElementAt(y).AppName);// and here
                }
            }
        }

        var AppName = Appname2.ToList();// and you've got you List<string> as the result

请试试这段代码,让我知道它是如何工作的(尽管我认为它应该工作得更快)。希望这可以帮助。

更新
终于到家了,抱歉耽搁了。我玩了一点代码,并通过将 last 重写for为以下代码使其更快:

foreach (var app in appList)
            {
                foreach (string li in allApps) 
                {
                    bool istrueapp = app.AppName.Equals(li);
                    if (istrueapp)
                    {
                        Appname2.AddLast(app.AppName);
                    }
                }
            }

这给了很大的加速,至少在我的机器上(r)。
请检查它是否在您的环境中更快。
希望有帮助。

于 2013-09-17T20:39:36.817 回答
0

您应该将 allApps 保存在由 appname 键入的字典中。要检查应用程序是否存在于 appList 中,只需查找 allApps.Contains(li)。

问题很可能源于最后一个 for 循环,它的复杂性看起来像 O(n^2)。使用字典应该将复杂性降低到 O(n*logn) 从而解决问题。

于 2013-09-17T19:44:49.087 回答
0

正如在另一个答案中已经评论List过的,在处理大量元素和执行简单操作时,a 效率不是很高。在这些条件下,更简单的集合(例如Array)代表更有效的解决方案。示例代码(适用于处理“普通”数组;您可以将其与当前列表或数组一起使用,以防开始使用它们):

List<string> Appname = new List<string>();
roster = MURLEngine.GetUserFriendDetails(token, userId);
foreach (string item in roster.RosterEntries)
{
    if(item == null || item.Trim().Length < 1) continue;
    if (item[0] == 'm' && Convert.ToInt32(item[1]) >= 0 && Convert.ToInt32(item[1]) <= 9)
    {
        var roster2 = MURLEngine.GetUserFriendDetails(token, item);
        foreach (string item2 in roster2.RosterEntries)
        {
            if(item2 == null || item2.Trim().Length < 1) continue;
            if (item2[0] != 'm')
            {
                bool found = false;
                foreach (string app in appList)
                {
                    if(app == null || app.Trim().Length < 1) continue;
                    if (app.AppName == item2)
                    {
                        found = true;
                        break;
                    }
                }
                if (found) Appname.Add(item2);
            }
        }
    }
}

如您所见,我忽略了中间存储allApps(也可以通过查询在您的版本中完成)。

与原始版本相比,此代码应提供显着改进(主要是当您将列表转换为数组时)。如果对进一步加速此代码感兴趣,您应该考虑重新设计提供输入的方式的选项(从而避免可能是最耗时的部分:调用MURLEngine.GetUserFriendDetails两次)。最后,请记住,您可以通过将 存储在列表/数组中 来将 替换(string app in appList) loop为简单的条件 ( AppNames.Contains(item2)) 。AppNames

于 2013-09-23T19:34:06.457 回答