Лучший способ сравнить 1 миллион Список объектов с еще 1 миллионом Список объектов в c# - PullRequest
0 голосов
/ 09 января 2020

Я дифференцирую список из 1 миллиона объектов с другим списком из 1 миллиона объектов. Я использую для, foreach, но это занимает слишком много времени, чтобы перебрать этот список. Может ли кто-нибудь помочь мне лучший способ сделать это

var SourceList = new List<object>(); //one million 
var TargetList = new List<object>()); // one million

//getting data from database here
//SourceList with List of one million 
//TargetList with List of one million

var DifferentList = new List<object>();

//ForEach
SourceList.ToList().ForEach(m =>
    {
      if (!TargetList.Any(s => s.Name == m.Name))
            DifferentList.Add(m);
  });

 //for
 for (int i = 0; i < SourceList .Count; i++)
   {
    if (!TargetList .Any(s => s == SourceList [i].Name))
            DifferentList .Add(SourceList [i]);
  }



Ответы [ 4 ]

2 голосов
/ 09 января 2020

// получение данных из базы данных здесь

Вы получаете данные из системы, которая специализируется на сопоставлении, сортировке и фильтрации данных, в вашей оперативной памяти, которая по умолчанию еще не может выполнить эту задачу вообще. А затем вы пытаетесь отсортировать, отфильтровать и сопоставить себя.

Это не удастся. Независимо от того, как сильно вы стараетесь, крайне маловероятно, что ваш компьютер с одним программистом, работающим с соответствующим алгоритмом, превзойдет ваше специализированное аппаратное обеспечение, называемое сервером базы данных, за одну операцию, которую это программное обеспечение должно быть действительно хорошо запрограммировано командами экспертов и оптимизированы в течение многих лет.

Вы не go заходите в модный ресторан и не просите их дать вам огромные пакеты с сырьем, чтобы вы могли бросить их в большую неочищенную миску и приготовить в микроволновой печи дома. Нет. Вы заказываете хороший ди sh, потому что это будет намного лучше, чем все, что вы могли бы сделать сами.

Простой ответ: Не делайте этого . Не берите необработанные данные и копайтесь в них часами. Оставьте эту работу в базе данных. Это единственное, в чем он должен быть хорош. Используйте это сила. Напишите запрос, который даст вам результат, не получите необработанные данные, а затем воспроизведите базу данных самостоятельно.

1 голос
/ 09 января 2020

Я думаю, что это плохая идея, но IEnumerable magi c поможет вам.

Для начала, упростите свое выражение. Выглядит это так:

var result = sourceList.Where(s => targetList.Any(t => t.Equals(s)));

Я рекомендую сделать сравнение в методе Equals:

public class CompareObject
{
    public string prop { get; set; }

    public new bool Equals(object o)
    {
        if (o.GetType() == typeof(CompareObject))
            return this.prop == ((CompareObject)o).prop;    
        return this.GetHashCode() == o.GetHashCode();
    }
}    

Далее добавить AsParallel. Это может как ускорить, так и замедлить вашу программу. В вашем случае вы можете добавить ...

var result = sourceList.AsParallel().Where(s => !targetList.Any(t => t.Equals(s)));

Процессор загружен на 100%, если вы попытаетесь перечислить все сразу, как это:

var cnt = result.Count();

Но вполне допустимо работать, если Вы получаете результаты небольшими порциями.

result.Skip(10000).Take(10000).ToList();

Полный код:

static Random random = new Random();
public class CompareObject
{
    public string prop { get; private set; }

    public CompareObject()
    {
        prop = random.Next(0, 100000).ToString();
    }

    public new bool Equals(object o)
    {
        if (o.GetType() == typeof(CompareObject))
            return this.prop == ((CompareObject)o).prop;    
        return this.GetHashCode() == o.GetHashCode();
    }
}

void Main()
{
    var sourceList = new List<CompareObject>();
    var targetList = new List<CompareObject>();
    for (int i = 0; i < 10000000; i++)
    {
        sourceList.Add(new CompareObject());
        targetList.Add(new CompareObject());
    }

    var stopWatch = new Stopwatch();

    stopWatch.Start();
    var result = sourceList.AsParallel().Where(s => !targetList.Any(t => t.Equals(s)));


    var lr = result.Skip(10000).Take(10000).ToList();
    stopWatch.Stop();

    Console.WriteLine(stopWatch.Elapsed);
}

Обновление

Я вспомнил, что вы можете использовать Hashtable. Выберите уникальные значения от targetList и от sourceList, затем заполните результат, значения которого не targetList.

Пример:

static Random random = new Random();
public class CompareObject
{
    public string prop { get; private set; }
    public CompareObject()
    {
        prop = random.Next(0, 1000000).ToString();
    }

    public new int GetHashCode() {
        return prop.GetHashCode();
    }
}


void Main()
{
    var sourceList = new List<CompareObject>();
    var targetList = new List<CompareObject>();
    for (int i = 0; i < 10000000; i++)
    {
        sourceList.Add(new CompareObject());
        targetList.Add(new CompareObject());
    }

    var stopWatch = new Stopwatch();

    stopWatch.Start();
    var sourceHashtable = new Hashtable();
    var targetHashtable = new Hashtable();

    foreach (var element in targetList)
    {
        var hash = element.GetHashCode();
        if (!targetHashtable.ContainsKey(hash))
            targetHashtable.Add(element.GetHashCode(), element);
    }

    var result = new List<CompareObject>();
    foreach (var element in sourceList)
    {
        var hash = element.GetHashCode();
        if (!sourceHashtable.ContainsKey(hash))
        {
            sourceHashtable.Add(hash, element);
            if(!targetHashtable.ContainsKey(hash)) {
                result.Add(element);
            }
        }
    }

    stopWatch.Stop();

    Console.WriteLine(stopWatch.Elapsed);
}
1 голос
/ 09 января 2020

Сканирование списка целей на соответствие имени является операцией O (n), поэтому ваш l oop равен O (n ^ 2). Если вы построите HashSet<string> из всех отдельных имен в целевом списке, вы можете проверить, существует ли имя в наборе за O (1) время, используя метод Contains.

0 голосов
/ 09 января 2020

Foreach выполняет нулевую проверку перед каждой итерацией, поэтому использование стандарта для l oop обеспечит немного лучшую производительность, с которой будет трудно справиться.

Если это займет слишком много времени, можете ли вы сломаться? сбор в меньшие наборы и / или обработку их параллельно?

Также вы можете посмотреть PLinq (Parallel Linq) , используя .AsParallel()

Другие области для улучшения: Используемые вами фактические логи c, а также то, как данные хранятся в памяти, в зависимости от вашей проблемы, вам может не потребоваться загружать весь объект в память для каждой итерации.

Пожалуйста, предоставьте пример кода, чтобы мы могли оказать дальнейшую помощь, когда такие большие объемы данных связаны с ухудшением производительности.

Опять же, в зависимости от времени, о котором мы здесь говорим, вы можете загрузить данные в базу данных и использовать их для сравнения, а не пытаться сделать это изначально в C#, этот тип решения лучше Это относится к наборам данных, которые уже находятся в базе данных или данные изменяются гораздо реже, чем время, необходимое для сравнения.

...