有没有更好的方法(最快)来获得最长的公共文件夹路径?
Posted
技术标签:
【中文标题】有没有更好的方法(最快)来获得最长的公共文件夹路径?【英文标题】:Is there a better way (fastest) to get the longest common folder path? 【发布时间】:2021-07-16 10:34:43 【问题描述】:我有一个文件夹列表, 想要得到最长的公共子串作为输出。
这是我的代码,好像不太好,
如何改进这些?
这些文件都来自我的RecursiveSearch
函数,可能是D:\123, E:\456, F:\a\e\eff,我保存到xml。
稍后从 xml 中读回,想要得到之前的决定。
文件可能有一万个。 我确实关心速度。
var li = new List<string>()
@"C:\Users\jared\Desktop\fld1\eumaps\4.jfif",
@"C:\Users\jared\Desktop\fld2\eumaps - (2)\4.jfif",
@"C:\Users\jared\Desktop\fld4\ade\4.jfif",
@"C:\Users\jared\Desktop\fld4\abc\S.png",
@"C:\Users\jared\Desktop\fld1\file\Snipaste_2021-07-07_03-03-45.png",
;
//var shortest1 = li.OrderBy(name => name.Length).FirstOrDefault();
string shortest = li.Aggregate((a1, a2) => a1.Length < a2.Length ? a1 : a2);
string longest = li.Aggregate((a1, a2) => a1.Length > a2.Length ? a1 : a2);
string common = string.Concat(shortest.TakeWhile((c, i) => c == longest[i]));
// C:\Users\jared\Desktop\fld NOT MY WANT CAUSE THERE IS NO SUCH FOLDER.
if (!Directory.Exists(common))
common = common.Replace(common.Split("\\").Last(), "");
【问题讨论】:
你保证有共同的路径吗? (即所有文件总是在 C 盘上吗?) @Damien_The_Unbeliever 是的。这些文件都来自 My RecursiveSearch 函数,可能是 D:\123, E:\456, F:\a\e\eff,我保存到 xml。我从 xml 回读,想要得到我之前的决定。 为什么需要更快的方法?您是否衡量过这是性能瓶颈? 你写:// C:\Users\jared\Desktop\fld NOT MY WANT.
那么你的预期结果是什么?
OP 可能想找到C:\Users\jared\Desktop
。
【参考方案1】:
您的方法将失败,因为您只是比较 shortest
和 longest
,如果有任何其他长度不同且中间有不同路径的路径。
根据我的理解,您希望输出到匹配的文件夹(不是文件夹或文件名的子字符串),即C:\Users\jared\Desktop\
这是我在 O(Nk) 解决方案中运行的解决方案,其中 N 是路径数,k 是最短可用长度。
工作示例代码here。
这也可以使用 Trie 数据结构以更优化的方式 (O(N + k)) 完成,但构建 Trie 需要额外的空间
var folders = new List<string>()
@"C:\Users\jared\Desktop\fld1\eumaps\4.jfif",
@"C:\Users\jared\Desktop\fld2\eumaps - (2)\4.jfif",
@"C:\Users\jared\Desktop\fld4\ade\4.jfif",
@"C:\Users\jared\Desktop\fld4\abc\S.png",
@"C:\Users\jared\Desktop\fld1\file\Snipaste_2021-07-07_03-03-45.png",
;
var minPathLength = folders.Min(x => x.Length);
var maxCommonPath = new StringBuilder();
var currentCommonPath = new StringBuilder();
for (int i = 0; i < minPathLength; i++)
var boolAllSame = true;
var c = folders[0][i];
boolAllSame = folders.All(x => x[i] == c);
if (boolAllSame)
currentCommonPath.Append(c);
if (c == '\\')
maxCommonPath.Append(currentCommonPath.ToString());
currentCommonPath = new StringBuilder();
else
break;
var result = maxCommonPath.ToString();
Console.WriteLine(result);
【讨论】:
如果输入路径仍然需要更多时间,请尝试使用运行速度更快的 Trie 数据结构。 您可以考虑比较不区分大小写的字符 (Char.ToUpperInvariant
),以允许匹配具有大小写差异的相等路径。
@TheodorZoulias,你是对的,但由于我们不确定输入,让 Jared 决定他想要什么。感谢您提出这个问题。【参考方案2】:
这是一个使用 Linq 的简洁但不是特别高效的实现。它还依赖于MoreLinq 包,对于Transpose
运算符:
var paths = new List<string>()
@"C:\Users\jared\Desktop\fld1\eumaps\4.jfif",
@"C:\Users\jared\Desktop\fld2\eumaps - (2)\4.jfif",
@"C:\Users\jared\Desktop\fld4\ade\4.jfif",
@"C:\Users\jared\Desktop\fld4\abc\S.png",
@"C:\Users\jared\Desktop\fld1\file\Snipaste_2021-07-07_03-03-45.png",
;
string[] longestCommonPathComponents = paths
.Select(path => path.Split(Path.DirectorySeparatorChar))
.Transpose()
.Select(parts => parts.Distinct(StringComparer.OrdinalIgnoreCase))
.TakeWhile(distinct => distinct.Count() == 1)
.Select(distinct => distinct.First())
.ToArray();
string longestCommonPath = Path.Combine(longestCommonPathComponents);
Console.WriteLine($"Longest common path: longestCommonPath");
输出:
最长公共路径:C:/Users/jared/Desktop
Try it on fiddle.
Transpose
操作符的签名:
// Transposes a sequence of rows into a sequence of columns.
public static IEnumerable<IEnumerable<T>> Transpose<T>(
this IEnumerable<IEnumerable<T>> source);
【讨论】:
【参考方案3】:var li = new List<string>()
@"C:\Users\jared\Desktop\fld1\eumaps\4.jfif",
@"C:\Users\jared\Desktop\fld2\eumaps - (2)\4.jfif",
@"C:\Users\jared\Desktop\fld4\ade\4.jfif",
@"C:\Users\jared\Desktop\fld4\abc\S.png",
@"C:\Users\jared\Desktop\fld1\file\Snipaste_2021-07-07_03-03-45.png",
;
string first = li.First();
int n = 0;
while (li.All(x => x.Length > n && x[n] == first[n]))
n++;
string longestCommon = first.Substring(0, n); // C:\Users\jared\Desktop\fld
你说C:\Users\jared\Desktop\fld
不是你想要的,而是你想要的?最嵌套的有效文件夹?只需拉到最后一个斜线,或使用 Path 方法来获取您想要的位。
【讨论】:
没有这样的文件夹:C:\Users\jared\Desktop\fld 所以按照我的建议做,然后拉到最后一个斜线?例如var folder = longestCommon.Substring(0, longestCommon.LastIndexOf('\'));
【参考方案4】:
有一个很好且快速的方法。好吧,你犯了一个大错误。 您不应该将文件保存在桌面上。它们必须位于项目路径和 bin\debug 文件夹中。也许你认为文件路径变长了,但是有一行代码是短而优化的。
var li = new List<string>()
Application.StartupPath + "/Images/1.png",
Application.StartupPath + "/Images/2.png",
Application.StartupPath + "/Images/3.png",
【讨论】:
你真的读过这个问题吗?这根本没有任何相关性。 应用程序将xml保存在应用程序文件夹中,xml文件记录Desktop文件夹中的文件。以上是关于有没有更好的方法(最快)来获得最长的公共文件夹路径?的主要内容,如果未能解决你的问题,请参考以下文章