internal static string FolderAwareEditDistance(string source, string[] targets) { if (targets.Length == 0) { return(null); } var separator = '/'; var sourceParts = source.Split(separator); var sourceFolders = sourceParts.Reverse().Skip(1).ToList(); var sourceFile = sourceParts.Last(); int missingFolderPenalty = 4; int extraFolderPenalty = 3; var scores = targets.Select(target => { var targetParts = target.Split(separator); var targetFolders = targetParts.Reverse().Skip(1).ToList(); var targetFile = targetParts.Last(); var commonFolders = sourceFolders.Where(x => targetFolders.Contains(x)); var reducedSourceFolders = sourceFolders.Except(commonFolders).ToList(); var reducedTargetFolders = targetFolders.Except(commonFolders).ToList(); int score = 0; int folderDiff = reducedSourceFolders.Count - reducedTargetFolders.Count; if (folderDiff > 0) { score += folderDiff * missingFolderPenalty; } else if (folderDiff < 0) { score += -folderDiff * extraFolderPenalty; } if (reducedSourceFolders.Count > 0 && reducedSourceFolders.Count >= reducedTargetFolders.Count) { foreach (var item in reducedTargetFolders) { int min = Int32.MaxValue; foreach (var item2 in reducedSourceFolders) { min = Math.Min(min, LevenshteinDistance.Compute(item, item2)); } score += min; } } else if (reducedSourceFolders.Count > 0) { foreach (var item in reducedSourceFolders) { int min = Int32.MaxValue; foreach (var item2 in reducedTargetFolders) { min = Math.Min(min, LevenshteinDistance.Compute(item, item2)); } score += min; } } score += LevenshteinDistance.Compute(targetFile, sourceFile); return(new { Target = target, Score = score }); }); var b = scores.OrderBy(x => x.Score); return(scores.OrderBy(x => x.Score).First().Target); }