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,但它更慢。
我的问题是我应该在这个场景中使用什么数据结构?
真的会帮助我
答案 0 :(得分: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();
答案 1 :(得分:1)
好的,到目前为止我可以提出什么建议。
首先:你有很多Add
的
一般来说,默认List<T>
不是Add
批量的最佳数据结构,因为它在内部实现为数组,当数据已满时会被销毁并复制到较大的数组中。
有两种选择:
- 创建具有预定义容量的列表:List<string> allApps = new List<string>(countOfApps);
。如果您可以提前大致计算要添加到列表中的项目数,那么这个很好
- 使用LinkedList<string> allApps = new LinkedList<string>()
。 LinkedList确实可以非常快速地添加新项目。
List<string> Appname = new List<string>();
列表也是如此。
其次:在开头你有distinct
的列表,然后在foreach
- 循环的每次迭代中转换为列表,而新构建的list不在该循环中使用。所以在这里你可以将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
请尝试使用此代码并告诉我它是如何工作的(虽然我认为它的工作速度要快得多)。 希望这会有所帮助。
<强>更新强>
最后我回家了,抱歉拖延。我使用了一些代码并通过将最后for
重写为此代码来加快速度:
foreach (var app in appList)
{
foreach (string li in allApps)
{
bool istrueapp = app.AppName.Equals(li);
if (istrueapp)
{
Appname2.AddLast(app.AppName);
}
}
}
这至少在我的机器(r)上提供了极大的加速 请检查您的环境是否更快 希望有所帮助。
答案 2 :(得分:0)
您应该将allApps保存在由appname键入的字典中。要检查应用程序是否存在于appList中,只需查找allApps.Contains(li)。
问题很可能源于最后一个for循环,其复杂性似乎是O(n ^ 2)。使用dictinoary应该将复杂性降低到O(n * logn),从而解决问题。
答案 3 :(得分:0)
正如在另一个答案中已经评论过的那样,List
在处理大量元素和执行简单操作时效率不高。更简单的集合(例如,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
存储在List / Array中,您可以使用简单条件(AppNames.Contains(item2)
)替换AppNames
。