Подтвердить что ты не робот

Количество элементов в списке <Список <T>>

У меня есть List<List<T>>. Как я могу считать все элементы в этом, как если бы это был один List<T> самым быстрым способом?

До сих пор я использовал

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

но это фактически создает список, а затем подсчитывает элемент, который не очень хорошая идея.

4b9b3361

Ответ 1

Я бы порекомендовал простой, вложенный цикл с HashSet, если вам нужно устранить дубликаты между списками. Он объединяет операции SelectMany и Distinct в заданную логику вставки и должен быть быстрее, так как HashSet имеет O (1) время поиска. Internal Distinct() может фактически использовать что-то подобное, но это полностью исключает построение единственного списка.

var set = new HashSet<T>();
foreach (var list in listOfLists)
{
    foreach (var item in list)
    {
        set.Add(item);
    }
}
var result = set.Count;

Ответ 2

Используя LINQ, я думаю, что ваш код хорош с небольшими изменениями, которые не нуждаются в .ToList(), просто вызовите расширение Count() следующим образом:

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

Ответ 3

Чтобы подсчитать все элементы во всех списках в списке, вы можете использовать агрегирующие операторы:

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

Ответ 4

Я хотел бы получить шанс ответить на этот вопрос, просто чтобы выделить, когда мы должны использовать 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

}

отдельная версия, использующая для (например,). В этом случае я создаю очень "узкое место", которое делает отчетливое, и оно еще быстрее.

 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;
                }
            }
        }

    }