Search code examples
c#selectfilterfinddataview

Find next higher value in DataView row


I have a DataView which in the row PathName contains names like:

"C:\$Recycle.Bin\S-1-5-21-1993492240-2256127134-121505747-1000"
"C:\$Recycle.Bin\S-1-5-21-1993492240-2256127134-121505747-1004"
"C:\Program Files (x86)\Common Files\microsoft shared\DAO\dao360.dll"
"C:\Program Files (x86)\Common Files\microsoft shared\ink\1.0\Microsoft.Ink.dll"
"C:\Program Files (x86)\Common Files\microsoft shared\ink\de-DE\InkObj.dll.mui"
"C:\Windows\System32\de-DE\Query.dll.mui"
"C:\Windows\System32\de-DE\query.exe.mui"
"C:\Windows\System32\de-DE\quser.exe.mui"
"C:\Windows\System32\de-DE\Qutil.dll.mui"
"C:\Windows\System32\DriverStore\FileRepository\bth.inf_amd64_neutral_de0494b6391d872c\bthport.sys"
"C:\Windows\System32\DriverStore\FileRepository\bth.inf_amd64_neutral_de0494b6391d872c\BTHUSB.SYS"
"C:\Windows\System32\DriverStore\FileRepository\bth.inf_amd64_neutral_e54666f6a3e5af91\bthenum.sys"

For any given path I need to get the subfolders.

Sub folders for the path "C:\"

"$Recycle.Bin"
"Program Files (x86)"
"Windows"

What I am currently doing is:

  • Extend the present rowfilter: MyDataView.rowfilter += " and (PathName LIKE 'c:\%')"
  • First I find C:\$Recycle.Bin\S-1-5-21-1993492240-2256127134-121505747-1000 and extract C:\$Recycle.Bin
  • Then I iterate through the rows till I find something different from C:\$Recycle.Bin, like C:\Program Files (x86)\...

The DataView may contain 100.000 and more entries so this way takes very long.

One possibility would be to extend the rowfilter after every hit:

MyDataView.rowfilter += " and (PathName LIKE 'c:\%')" + " and (PathName NOT LIKE 'C:\$Recycle.Bin\%')". 

But the path names may get very long and this will lead to a stack overflow in the rowfilter.

Is there any other way, like "get the next higher value"?

Edit
The subfolders must be found for any given path not only for c:\


Solution

  • If I understand you correctly this could be done with a single line of Linq (Splitted in more than one line for readability)

    var dirs = dv.Table
                 .AsEnumerable()
                 .Select(x => Path.GetDirectoryName(x.Field<string>("PathName")))
                 .Distinct();
    

    The trick consist in using the Path.GetDirectoryName to extract from each row the value of the field PathName and, using the Select method, create an enumerable of strings. Then the Distinct method returns just the unique directory names from the collection.

    If your DataView has been filtered for some other condition and you want to keep this condition to exclude a subset of records then you could use the Where method to extract the required records. For example, to exclude every record that starts with "C:\WINDOWS" you could write

    var dirs = dv.Table
                 .AsEnumerable()
                 .Where(k => !k.Field<string>("PathName").StartsWith(@"C:\WINDOWS"))
                 .Select(x => Path.GetDirectoryName(x.Field<string>("PathName")))
                 .Distinct();