У меня есть метод, который выполняет упрощенный 'grep' для файлов, используя множество «строк поиска». (По сути, я делаю очень наивный "Найти все ссылки")
IEnumerable<string> searchStrings = GetSearchStrings();
IEnumerable<string> filesToLookIn = GetFiles();
MultiMap<string, string> references = new MultiMap<string, string>();
foreach( string fileName in filesToLookIn )
{
foreach( string line in File.ReadAllLines( fileName ) )
{
foreach( string searchString in searchStrings )
{
if( line.Contains( searchString ) )
{
references.AddIfNew( searchString, fileName );
}
}
}
}
Примечание: MultiMap<TKey,TValue>
примерно такое же, как Dictionary<TKey,List<TValue>>
, просто избегая исключений NullReferenceException, с которыми вы обычно сталкиваетесь.
<Ч />
Я пытался перевести это в более «функциональный» стиль, используя цепные методы расширения LINQ, но не понял этого.
Одна тупиковая попытка:
// I get lost on how to do a loop within a loop here...
// plus, I lose track of the file name
var lines = filesToLookIn.Select( f => File.ReadAllLines( f ) ).Where( // ???
И еще один (надеюсь, сохранив имя файла на этот раз):
var filesWithLines =
filesToLookIn
.Select(f => new { FileName = f, Lines = File.ReadAllLines(f) });
var matchingSearchStrings =
searchStrings
.Where(ss => filesWithLines.Any(
fwl => fwl.Lines.Any(l => l.Contains(ss))));
Но я все еще теряю информацию, которая мне нужна.
Может быть, я просто подхожу к этому не с того угла? С точки зрения производительности циклы должны работать примерно в том же порядке, что и в исходном примере.
Есть идеи, как это сделать в более компактном функциональном представлении?