gpt4 book ai didi

c# - 如何使用 LINQ 使 C# 'grep' 更具功能性?

转载 作者:太空狗 更新时间:2023-10-29 17:45:37 25 4
gpt4 key购买 nike

我有一个方法可以跨文件执行简单的“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>>大致相同,只是避免了您通常会遇到的 NullReferenceExceptions。


我一直在尝试使用链接的 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))));

但我似乎仍然丢失了我需要的信息。

也许我只是从错误的角度来处理这个问题?从性能的角度来看,循环应该按照与原始示例大致相同的顺序执行。

关于如何在更紧凑的函数表示中做到这一点有什么想法吗?

最佳答案

怎么样:

var matches =
from fileName in filesToLookIn
from line in File.ReadAllLines(fileName)
from searchString in searchStrings
where line.Contains(searchString)
select new
{
FileName = fileName,
SearchString = searchString
};

foreach(var match in matches)
{
references.AddIfNew(match.SearchString, match.FileName);
}

编辑:

从概念上讲,查询将每个文件名转换为一组行,然后将该组行交叉连接到一组搜索字符串(意味着每一行都与每个搜索字符串配对)。该集合被过滤为匹配行,并选择每行的相关信息。

多个from 子句类似于嵌套的foreach 语句。每个都表示前一个范围内的新迭代。多个 from 子句转换为 SelectMany方法,从每个元素中选择一个序列,并将结果序列展平为一个序列。

C# 的所有查询语法都转换为扩展方法。然而,编译器确实使用了一些技巧。一种是使用匿名类型。每当 2+ 范围变量在同一范围内时,它们可能是幕后匿名类型的一部分。这允许任意数量的作用域数据流过扩展方法,如 SelectWhere,它们具有固定数量的参数。参见 this post了解更多详情。

下面是上述查询的扩展方法翻译:

var matches = filesToLookIn
.SelectMany(
fileName => File.ReadAllLines(fileName),
(fileName, line) => new { fileName, line })
.SelectMany(
anon1 => searchStrings,
(anon1, searchString) => new { anon1, searchString })
.Where(anon2 => anon2.anon1.line.Contains(anon2.searchString))
.Select(anon2 => new
{
FileName = anon2.anon1.fileName,
SearchString = anon2.searchString
});

关于c# - 如何使用 LINQ 使 C# 'grep' 更具功能性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1122084/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com