我有List<List<T>>
。
如何以最快的方式计算其中的所有元素,就像它是单个List<T>
一样?
到目前为止,我已经使用了
List<int> result = listOfLists
.SelectMany(list => list)
.Distinct()
.ToList().Count;
但这实际上会创建一个列表,然后计算一个不是一个好主意的元素。
答案 0 :(得分:15)
通过使用LINQ,我认为您的代码很好,只需要对.ToList()
进行一些更改,只需按以下方式调用Count()
扩展名:
int result = listOfLists.SelectMany(list => list).Distinct().Count();
答案 1 :(得分:14)
如果您需要消除列表之间的重复,我建议使用带有HashSet的简单嵌套循环。它将SelectMany和Distinct操作组合到集合插入逻辑中,并且应该更快,因为HashSet具有O(1)查找时间。内部Distinct()实际上可能使用类似的东西,但这完全省略了单个列表的构造。
var set = new HashSet<T>();
foreach (var list in listOfLists)
{
foreach (var item in list)
{
set.Add(item);
}
}
var result = set.Count;
答案 2 :(得分:7)
要计算列表中所有列表中的所有元素,您可以使用聚合运算符:
int count = listOfLists.Sum(l => l.Distinct().Count());
答案 3 :(得分:1)
我想有机会回答这个问题,只是为了突出我们何时应该使用linq以及什么时候使用linq。 不幸的是,今天人们并不关心性能,因为我们习惯于在非常强大的计算机上工作。无论如何只需尝试下面的代码,你会发现Linq比版本的经典慢100多倍。只有当您需要编写的表达式非常复杂且您希望使其更具可读性时,才应使用Linq。 我没有把时间花在下面的解决方案上,因为我想专注于性能
public static void Main(string [] arg)
{
//create the list
List<List<string>> listOfList = new List<List<string>>()
{
new List<string>()
{
"1.1","2.2"
}
,
new List<string>()
{
"2.1","2.2","2.3"
}
};
//stopwatch using Linq
Stopwatch stopwatch=new Stopwatch();
stopwatch.Start();
int totalUsingLinq = listOfList.Sum(x => x.Count);
stopwatch.Stop();
Console.WriteLine("Using Linq:{0}",stopwatch.Elapsed); //00005713
int totalUsingFor = 0;
//stopwatch using classic for
stopwatch.Reset();
stopwatch.Start();
totalUsingFor = 0;
for(int i=0;i<listOfList.Count;i++)
{
var mainItem = listOfList[i];
if(mainItem!=null)
{
totalUsingFor += mainItem.Count;
}
}
stopwatch.Stop();
Console.WriteLine("Using for:{0}", stopwatch.Elapsed); //0000010
}
使用for的不同版本(仅举例)。 在这种情况下,我创建了一个非常“瓶颈”的功能,它具有独特性,并且仍然更快。
public class Program
{
public static void Main(string[] arg)
{
//create the list
List<List<string>> listOfList = new List<List<string>>()
{
new List<string>()
{
"1.1","2.2","1.1","1.1","2.2","1.1","1.1","2.2","1.1","1.1"
}
,
new List<string>()
{
"2.1","2.2","2.3","2.3","1.1","2.2","1.1","1.1","2.2","1.1","1.1","2.2","1.1","1.1","2.2","1.1","1.1","2.2","1.1"
}
};
//stopwatch using Linq
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int totalUsingLinq = listOfList.Sum(l => l.Distinct().Count());
stopwatch.Stop();
Console.WriteLine("Using Linq:{0}", stopwatch.Elapsed); //000012150
int totalUsingFor = 0;
//stopwatch using classic for
stopwatch.Reset();
stopwatch.Start();
totalUsingFor = 0;
for (int i = 0; i < listOfList.Count; i++)
{
var mainItem = listOfList[i];
if (mainItem != null)
{
for(int y=0;y<mainItem.Count;y++)
{
if(mainItem[y]!=null)
{
totalUsingFor++;
NullDuplicateItems(y, ref mainItem);
}
}
}
}
stopwatch.Stop();
Console.WriteLine("Using for:{0}", stopwatch.Elapsed); //0009440
}
public static void NullDuplicateItems(int index,ref List<string > list)
{
var item = list[index];
for(int i=index+1;i<list.Count;i++)
{
if(list[i]==item)
{
list[i] = null;
}
}
}
}