Сравните два списка, которые содержат много объектов (3-я часть) «эти объекты имеют другой тип» - PullRequest
1 голос
/ 21 мая 2011

Как я могу ускорить этот запрос linq?

Это занимает много времени, и когда я помещаю много объектов в список, я получаю исключение памяти.

List<DirectoryInfo> directoriesThatWillBeCreated = new List<DirectoryInfo>();
// some code to fill the list
// ..
// ..

List<FileInfo> FilesThatWillBeCopied = new List<FileInfo>();
// some code to fill the list
//....

directoriesThatWillBeCreated = (from a in FilesThatWillBeCopied
                                from b in directoriesThatWillBeCreated
                                where a.FullName.Contains(b.FullName)
                                select b).ToList();

Я надеюсь, что смогу сделать что-то вроде предыдущее решение , но я не знаю, как это сделать при работе с различными типами объектов. Нужно ли создавать новый класс, затем преобразовывать все объекты FileInfo и DirectoryInfo в этот класс, а затем выполнять запрос? Более того, классы FileInfo и DirectoryInfo запечатаны, и я не могу наследовать их, поэтому мне придется создать новый класс, и это будет неэффективно. По крайней мере, это будет более эффективным, чем этот запрос, потому что этот запрос занимает вечность.

Ответы [ 3 ]

0 голосов
/ 21 мая 2011

Одна вещь, которую вы можете сделать, это изменить Contains на StartsWith . StartsWith быстрее провалится в случае неудачного совпадения.

directoriesThatWillBeCreated = (from a in FilesThatWillBeCopied
                                from b in directoriesThatWillBeCreated
                                where a.FullName.StartsWith(b.FullName)
                                select b).ToList();

Это не полное решение, хотя. Если FilesThatWillBeCopied имеет M элементов, а directoriesThatWillBeCreated имеет N элементов, то ваш запрос будет обрабатывать сравнения строк MxN.

Другой вариант

Еще одна оптимизация, чтобы попробовать, сначала переберите directoriesThatWillBeCreated, затем выберите те, которые соответствуют любому FileInfo в FilesThatWillBeCopied. Проверяя, есть ли совпадение, вы можете прервать тестирование файлов, как только совпадение будет найдено. Это можно сделать так: (предупреждение, код блокнота следует)

directoriesThatWillBeCreated = directoryThatWillBeCreated
    .Select(b => FilesThatWillBeCopied
    .Any(a => a.FullName.StartsWith(b.FullName)));
0 голосов
/ 21 мая 2011

Я бы предложил использовать HashSet<DirectoryInfo> для сравнений, но, к сожалению, DirectoryInfo не имеет должных реализаций сравнения на равенство, поэтому нужно будет использовать строки.(Другим вариантом будет реализация вашего собственного IComparer<DirectoryInfo>.) Кроме того, вы должны использовать StringComparer.InvariantCultureIgnoreCase в именах, если вы не уверены, что обе коллекции имеют одинаковый регистр.

var dirs = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
// fill dirs

var files = new List<FileInfo>();
// fill files

var result = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);

foreach (var file in files)
{
    var dir = file.Directory;
    while (dir != null && !result.Contains(dir.FullName))
    {
        if (dirs.Contains(dir.FullName))
            result.Add(dir.FullName);
        dir = dir.Parent;
    }
}

Это решение не 't вообще не использовать LINQ, но это часто бывает, когда вам не хватает производительности, а самое простое решение LINQ слишком медленное.

0 голосов
/ 21 мая 2011

Это медленно, потому что код выполняет линейный поиск в списке каталогов для каждого файла.Попробуйте:

var dirlist = FilesThatWillBeCopied
    .Select(f => Directory.GetParent(f.FullName))
    .GroupBy(d => d.FullName)

Возможно, вам придется немного поиграть с синтаксисом, но, надеюсь, вы поймете смысл.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...