What is the best way extract the common file path from the list of file path strings in c#?
Eg: I have a list 5 file paths in List variable, like below
c:\
Because everything is best solved with LINQ*:
*not everything is best solved with LINQ.
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Program
{
static void Main(string[] args)
{
List<string> Files = new List<string>()
{
@"c:\abc\pqr\tmp\sample\b.txt",
@"c:\abc\pqr\tmp\new2\c1.txt",
@"c:\abc\pqr\tmp\b2.txt",
@"c:\abc\pqr\tmp\b3.txt",
@"c:\a.txt"
};
var MatchingChars =
from len in Enumerable.Range(0, Files.Min(s => s.Length)).Reverse()
let possibleMatch = Files.First().Substring(0, len)
where Files.All(f => f.StartsWith(possibleMatch))
select possibleMatch;
var LongestDir = Path.GetDirectoryName(MatchingChars.First());
}
}
The first line gets a list of lengths of possible matches to evaluate. We want the longest possibility first (so i reverse the enumeration which would be 0, 1, 2, 3; turning it into 3, 2, 1, 0).
I then get the string to match, which is simply a substring of the first entry of the given length.
I then filter the results, to ensure we only include possible matches that all files start with.
Finally, i return the first result, which will be the longest substring and call path.getdirectoryname to ensure if something has a few identical letters in the filenames it isn't included.
Keep a tally of each segment and keep going while all the paths start with the tally.
void Main()
{
string[] paths = new[] { @"c:\abc\pqr\tmp\sample\b.txt",
@"c:\abc\pqr\tmp\new2\c1.txt",
@"c:\abc\pqr\tmp\b2.txt",
@"c:\abc\pqr\tmp\b3.txt",
@"c:\abc\pqr\tmp\tmp2\b2.txt"};
var test = new List<string>();
var common = paths[0].Split('\\').TakeWhile ( segment =>
{
test.Add ( segment );
return paths.All ( path => path.StartsWith ( String.Join ("\\", test ) + "\\") ) ;
} );
Console.WriteLine ( String.Join ("\\", common ) );
}
The selected solution does not work properly if one of the paths is exactly the directory name that should be returned. I think there should be:
from len in Enumerable.Range(0, matchingNames.Min(s => s.Length) + 1).Reverse()