Question

I'm trying to remove from DirectoryInfo dInfoA where dInfoA has Directories that are listed in 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);

The folder structure is this:

C:\apples
C:\apples\oranges
C:\apples\banannas

I want to take the directory info from A and B and remove C:\Apples\Oranges from A because it exists B.

Is there a way to do this in LINQ, or a way to do this at all?

Was it helpful?

Solution

This can be done simply enough. Create a set (that can be much more efficiently searched than a List or array) of all of the paths in the second directory. Then you can easily write a query to give you all of the items where the directory path is in that set (or not in that set, if that's what you want). Note the Comparer is passed to the set to ensure it does a case insensitive comparison.

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

OTHER TIPS

GetDirectories won't get the base directory, so B would be empty. You must add the root so you can achieve your goal.

Check this out:

  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();

You could use MoreLINQ and ExceptBy:

dInfoB = dInfoB.ExceptBy(dInfoA, n => n.FullName, 
    StringComparer.InvariantCultureIgnoreCase).ToArray();

If you don't have access to MoreLINQ, you could also use this (slightly) less efficient way:

dInfoB = dInfoB.Except(dInfoA, 
    PropertyEqualityComparer.GetNew<DirectoryInfo, string>
    (n => n.FullName, StringComparer.InvariantCultureIgnoreCase)).ToArray();

Still a lot more efficient than Where + Any.

if I get what you're trying to do. The extra comparer is because DirectoryInfo decides that it doesn't want to override Equals.

The comparer is this:

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));
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top