Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 计算列表中元素的数量<;列表<;T>&燃气轮机;_C#_Linq - Fatal编程技术网

C# 计算列表中元素的数量<;列表<;T>&燃气轮机;

C# 计算列表中元素的数量<;列表<;T>&燃气轮机;,c#,linq,C#,Linq,我有一个列表。 如何以最快的方式将此列表中的所有元素都当作一个列表来计数 到目前为止,我已经使用了 List<int> result = listOfLists .SelectMany(list => list) .Distinct() .ToList().Count; List result=listofList .SelectMany(list=>list) .Distinct() .ToList().Count; 但这实际上创建了一个列表,然后对元素进行计

我有一个
列表
。 如何以最快的方式将此列表中的所有元素都当作一个
列表来计数

到目前为止,我已经使用了

List<int> result = listOfLists
  .SelectMany(list => list)
  .Distinct()
  .ToList().Count;
List result=listofList
.SelectMany(list=>list)
.Distinct()
.ToList().Count;

但这实际上创建了一个列表,然后对元素进行计数,这不是一个好主意。

要对列表中所有列表中的所有元素进行计数,可以使用聚合运算符:

int count = listOfLists.Sum(l => l.Distinct().Count());

如果需要消除列表之间的重复项,我建议使用一个简单的嵌套循环和哈希集。它将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;
var set=newhashset();
foreach(列表中的var列表)
{
foreach(列表中的变量项)
{
设置。添加(项目);
}
}
var result=set.Count;

通过使用LINQ,我认为您的代码很好,有一些改动,不需要
.ToList()
,只需调用
Count()
扩展,如下所示:

int result = listOfLists.SelectMany(list => list).Distinct().Count();

我想有机会回答这个问题,只是想强调一下我们什么时候应该使用linq,什么时候应该使用经典。 不幸的是,今天人们不太关心性能,因为我们习惯了在功能强大的计算机上工作。不管怎样,只要尝试下面的代码,您就会发现Linq比classic for版本慢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

}
publicstaticvoidmain(字符串[]arg)
{
//创建列表
List listOfList=新列表()
{
新名单()
{
"1.1","2.2"
}
,
新名单()
{
"2.1","2.2","2.3"
}
};
//使用Linq的秒表
秒表秒表=新秒表();
秒表。开始();
inttotalusinglinq=listOfList.Sum(x=>x.Count);
秒表;
WriteLine(“使用Linq:{0}”,stopwatch.appeased);//00005713
int totalUsingFor=0;
//秒表使用经典的
秒表复位();
秒表。开始();
totalUsingFor=0;
for(int i=0;i l.Distinct().Count());
秒表;
WriteLine(“使用Linq:{0}”,stopwatch.appeased);//00001250
int totalUsingFor=0;
//秒表使用经典的
秒表复位();
秒表。开始();
totalUsingFor=0;
for(int i=0;ifor(int y=0;最快的方法可能是不使用linq并坚持使用for循环,不需要
.ToList()
,使用
Count()即可
extension这并不能消除列表之间的重复项,只能消除每个列表中的重复项。@lejon为什么要接受一个与原始代码不同的答案?tvanfosson和Horam的答案是正确的。应该会快一点,因为一些委托调用被消除了。Distinct已经使用了一个哈希集,其中包含了很多内容相同的逻辑。我看不到你在这里执行
SelectMany
。因此你当前的代码非常不同。@Homam--很好的捕获,它应该是一个嵌套循环。它基本上是相同的,只是不需要构造一个组合的内部列表来进行区分。这节省了内存,可能会缩短时间。你可以省去
包含
哈希集。Add
不会抱怨该项是否已经存在。@CodeInChaos-我希望Microsoft能够保持一致,字典会抛出一个异常——但是,我想在这种情况下,您可能会插入一个重复的键,而不是重复的项。@Shurdoof我很确定这会更慢。这个答案的要点是这很快。为了更好的可读性,可以使用Horam的答案。很可能比tvanfosson的答案慢一点。但它仍然是正确的,而且更简短/更容易阅读。您缺少了
独特的
功能,因此这是一个与OPs问题完全不同的问题。这两个例子都可能需要几微秒的时间ll列表与您的示例相同。因此,除非它们是it实践的瓶颈,否则这是在经典循环上使用linq的一个示例。当我运行它们每一个10万次时,因子是40,而不是>100,我没有像我所说的那样在代码上花费时间:即使您添加了distinct,它也至少会快500倍。在示例中,我没有创建一个巨大的l这是因为这只是一个例子,但如果你想试一试,你可以尝试我的代码对一个有数千个项目的列表,你会得到相同的结果。这是正常的,系数是40,而不是>100,因为你正在运行的机器是多任务的,所以它可能会发生窗口正在处理一些东西在你的测试,所以你应该运行它很多时间d然后计算平均值,但对于经典值来说,速度总是快得多:40倍很多!这就是为什么你要以经典的方式编写性能瓶颈代码。但是如果不是这样,就不用麻烦了。40倍几乎为零仍然几乎为零。
 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;
                }
            }
        }

    }