我有一个包含以下内容的文件:
Aulin: Performance Enhancers, Combat Stabilisers
i Bootis: Fish, Basic Medicines
Aulin: Agricultural Medicines, Combat Stabilisers
Eranin: Tea, Coffee
LP 98-132: Bertrandite,Gold
Dahan: Tantalum, Explosives
Asellus Primus: Resonant Separators, Non Lethal Weapons
LHS 3006: Bertrandite, Indite
这些是来自着名游戏的价值观。
现在我读取数据并使用以下代码将其转换为Dictionary
:
var imports = File.ReadAllText(@"d:\exports.txt");
var productsDict =
imports
.Split('\n')
.Select(line => line.Split(':'))
.GroupBy(line => line[0])
.ToDictionary(
line => line.Key,
line =>
line.Select(item => item[1])
.Aggregate((c, n) => c.Insert(c.Length, "," + n))
.Split(',')
.Select(i => i.Trim(' '))
.Distinct()
);
我可以优化LINQ吗?何时必须为链接lambda使用新标识符?如您所见,我使用line
,item
,i
等等。
答案 0 :(得分:2)
最快的方法(并不是很难实现)是逐行手动解析文件,然后是char-by-char。 (如果要进行解析性能)步骤:
:
出现。如果在您的情况下性能不是主键(文件不是很大),您可以将一些LINQ方法分组为单独的方法(例如扩展方法),如:
public static IEnumerable<string> SplitByLine(this string text)
{
return text.Split('\n');
}
public static IEnumerable<string[]> KeyValuesSplitted(this IEnumerable<string> lines)
{
return lines.Select(line => line.Split(':'));
}
public static IEnumerable<IGrouping<string[]>> GroupyByKey(this IEnumerable<string[]> keyValuesSplitted)
{
return keyValuesSplitted.GroupBy(line => line.First());
}
// and so on..
用法:
productsDict = imports.SplitByLine()
.KeyValuesSplitted()
.GroupyByKey() //and so on.
在这种情况下,每种方法都很容易理解,我们知道导入时会发生什么。
答案 1 :(得分:0)
您可以引入一些局部变量以使事物更具可读性。 使事物看起来更好,更易读的另一个技巧是将链中的每个函数调用放在一个新行上。这样,您可以从上到下读取代码,而不是向右滚动。
你应该将它包装在一个名为ConvertData()或ImportData()之类的方法中,或者甚至在单独的类中。这样你的代码看起来也更加可重复,因为你不必知道导入是如何完成的,并且你不会被复杂的代码分散注意力。
您可以这样做:
var imports = File.ReadAllText(@"d:\exports.txt");
var productsDict = importData(imports);
然后在一个单独的方法中,或者在一个单独的类中更好(除非这个类只负责导入数据):
private Dictionary<string, IEnumerable<string>> importData(string imports)
{
return imports.Split('\n')
.Select(line => line.Split(':'))
.GroupBy(line => line[0])
.ToDictionary(line => line.Key,
line => line.Select(item => item[1])
.Aggregate((c, n) => c.Insert(c.Length, ","+n))
.Split(',')
.Select(i => i.Trim(' '))
.Distinct()
);
}
更好,但可能超出问题范围,是创建一个IImporter接口,在界面中定义了导入方法,以便以后您可以随时切换Importer类,或支持多个Importers,而不会破坏其他部分你的代码
答案 2 :(得分:0)
首先,不是将整个文件加载到内存中,而是每次都可以读取每一行。
var lines = File.ReadLines(@"d:\exports.txt");
然后,您在框架中遗漏了许多可以使用的工具(例如string.Join
或SelectMany
),以及更简单的合成语:
var productDict = (from line in lines
let keyValue = line.Split(':')
let lineValues = from value in keyValue[1].Split(',')
select value.Trim()
group lineValues by keyValue[0] into entry
select new
{
entry.Key,
Entry = (from values in entry
from value in values
select value).Distinct(),
})
.ToDictionary(
entry => entry.Key,
entry => string.Join(",", entry.Entry));