Сравните два DirectoryInfo и удалите из A, где B существует. LINQ?
Я пытаюсь удалить из DirectoryInfo dInfoA, где dInfoA имеет каталоги, которые перечислены в dInfoB.
DirectoryInfo Dinfo = new DirectoryInfo(@"C:\Apples");
DirectoryInfo[] dInfoA = Dinfo.GetDirectories("*.*", SearchOption.AllDirectories);
DirectoryInfo DinfoB = new DirectoryInfo(@"C:\Apples\Oranges");
DirectoryInfo[] dInfoB = DinfoB.GetDirectories("*.*", SearchOption.AllDirectories);
Структура папок такая:
C: \ яблоки
C: \ яблоки \ апельсины
C: \ яблоки \banannas
Я хочу взять информацию каталога из A и B и удалить C:\Apples\Oranges из A, потому что она существует B.
Есть ли способ сделать это в LINQ, или способ сделать это вообще?
3 ответа
Это можно сделать достаточно просто. Создайте набор (который можно найти намного эффективнее, чем List
или массив) всех путей во втором каталоге. Затем вы можете легко написать запрос, чтобы дать вам все элементы, где путь к каталогу находится в этом наборе (или не в этом наборе, если это то, что вы хотите). Обратите внимание, что Comparer передается в набор, чтобы убедиться, что он выполняет сравнение без учета регистра.
var directoryBPaths = new HashSet<string>(dInfoB.Select(dir => dir.FullName),
StringComparer.InvariantCultureIgnoreCase);
var directoriesToRemove = dInfoA.Where(dir =>
directoryBPaths.Contains(dir.FullName));
//If you just want a sequence of the items not
//in the other set, get that directly
var directoriesToKeep = dInfoA.Where(dir =>
!directoryBPaths.Contains(dir.FullName));
Вы можете использовать MoreLINQ и ExceptBy
:
dInfoB = dInfoB.ExceptBy(dInfoA, n => n.FullName,
StringComparer.InvariantCultureIgnoreCase).ToArray();
Если у вас нет доступа к MoreLINQ, вы также можете использовать этот (немного) менее эффективный способ:
dInfoB = dInfoB.Except(dInfoA,
PropertyEqualityComparer.GetNew<DirectoryInfo, string>
(n => n.FullName, StringComparer.InvariantCultureIgnoreCase)).ToArray();
Все еще намного эффективнее, чем Where
+ Any
,
если я получу то, что вы пытаетесь сделать. Дополнительный компаратор объясняется тем, что DirectoryInfo решает, что он не хочет переопределять Equals
,
Сравнитель это:
public class PropertyEqualityComparer<TObject, TProperty>
: IEqualityComparer<TObject>
{
Func<TObject, TProperty> _selector;
IEqualityComparer<TProperty> _internalComparer;
public PropertyEqualityComparer(Func<TObject, TProperty> propertySelector,
IEqualityComparer<TProperty> innerEqualityComparer = null)
{
_selector = propertySelector;
_internalComparer = innerEqualityComparer;
}
public int GetHashCode(TObject obj)
{
return _selector(obj).GetHashCode();
}
public bool Equals(TObject x, TObject y)
{
IEqualityComparer<TProperty> comparer =
_internalComparer ?? EqualityComparer<TProperty>.Default;
return comparer.Equals(_selector(x), _selector(y));
}
}
GetDirectories
не получит базовый каталог, поэтому B
будет пустым. Вы должны добавить корень, чтобы вы могли достичь своей цели.
Проверь это:
DirectoryInfo rootA = new DirectoryInfo(@"C:\Apples");
List<DirectoryInfo> listA = rootA.GetDirectories("*.*", SearchOption.AllDirectories).ToList();
listA.Add(rootA);
DirectoryInfo rootB = new DirectoryInfo(@"C:\Apples\Oranges");
List<DirectoryInfo> listB = rootB.GetDirectories("*.*", SearchOption.AllDirectories).ToList();
listB.Add(rootB);
DirectoryInfo[] aDiffB = listA.Where(x => !listB.Any(y => string.Equals(y.FullName, x.FullName, StringComparison.InvariantCultureIgnoreCase))).ToArray();