我有这样的linq声明:
var records = from line in myfile
let data = line.Split(',')
select new { a=int.Parse(data[0]), b=int.Parse(data[1]) };
var average = records.Sum(r => r.b)!=0?records.Sum(r => r.a) / records.Sum(r => r.b):0;
我的问题是: 记录的次数是多少次。(r => r.b)是在最后一行计算的? LINQ是否每次需要计算总和时都会遍历所有记录(在这种情况下,3 Sum()所以循环3次)?或者它是否巧妙地循环遍历所有记录并计算所有总和?
修改1 :
我想知道是否有任何方法可以通过全部来改善它 记录只是一次(因为我们只需要在一个循环中完成它) 当使用plain for循环时)?
并且之前没有必要将所有内容加载到内存中 我们可以做总和和平均。当然,我们可以总结每个元素 从文件中加载它。有没有办法减少记忆 消费也是?
修改2
为了澄清一下,在我结束之前我没有使用LINQ。使用plain while / for循环可以实现所有性能要求。但我接着尝试通过使用LINQ来提高可读性并减少代码行。似乎我们无法同时获得两者。
答案 0 :(得分:9)
两次,像这样写,它会一次:
var sum = records.Sum(r => r.b);
var avarage = sum != 0 ? records.Sum(r => r.a)/sum: 0;
答案 1 :(得分:5)
很多的答案,但没有一个能够解决你的所有问题。
在最后一行计算记录数(r => r.b)多少次?
三次。
每次需要计算时,LINQ是否会遍历所有记录 一个总和(在这种情况下,3 Sum()所以循环3次)?
是
或者只是巧妙地遍历所有记录一次并计算所有记录 总和?
没有
我想知道是否有任何方法可以通过全部来改善它 记录只有一次(因为我们只需要在一个循环中完成它 使用plain for循环)?
你可以这样做,但它需要你急切地加载所有与下一个问题相矛盾的数据。
在我们之前,确实没有必要将所有内容加载到内存中 可以做总和和平均。当然,我们可以将每个元素相加 从文件中加载它。有没有办法减少记忆 消费也是?
那是对的。在原始帖子中,您有一个名为myFile
的变量,并且您正在迭代它并将其放入名为line
的本地变量中(读取:基本上是foreach
)。由于您没有显示获取myFile
数据的方式,因此我假设您急切地加载了所有数据。
以下是延迟加载数据的简单示例:
public IEnumerable<string> GetData()
{
using (var fileStream = File.OpenRead(@"C:\Temp\MyData.txt"))
{
using (var streamReader = new StreamReader(fileStream))
{
string line;
while ((line = streamReader.ReadLine()) != null)
{
yield return line;
}
}
}
}
public void CalculateSumAndAverage()
{
var sumA = 0;
var sumB = 0;
var average = 0;
foreach (var line in GetData())
{
var split = line.Split(',');
var a = Convert.ToInt32(split[0]);
var b = Convert.ToInt32(split[1]);
sumA += a;
sumB += b;
}
// I'm not a big fan of ternary operators,
// but feel free to convert this if you so desire.
if (sumB != 0)
{
average = sumA / sumB;
}
else
{
// This else clause is redundant, but I converted it from a ternary operator.
average = 0;
}
}
答案 2 :(得分:4)
三次,您应该使用的是return _.sum(_.pluck(dataset, 'cost'))
,而不是Aggregate
。
Sum
答案 3 :(得分:2)
对Sum方法的每次调用都会遍历myfile中的所有行。 要提高性能,请写:
var records = (from line in myfile
let data = line.Split(',')
select new { a=int.Parse(data[0]), b=int.Parse(data[1]) }).ToList();
所以它会创建包含所有元素的列表(带有“a”和“b”属性),然后每次调用Sum方法都会遍历此列表,而不会拆分和解析数据。 当然,你可以进一步记住一些临时变量中Sum方法的结果。
答案 4 :(得分:1)
*动态是一种快速解决方法。你应该为它编写一个结构。
int sum_a = 0,sum_b = 0;
Func<string[], dynamic> b = (string[] data) => {
sum_a += int.Parse(data[0]);
sum_b += int.Parse(data[1]);
return new {a = int.Parse(data[0]),b = int.Parse(data[0]) };
};
var records = from line in fileLines
let data = line.Split(',')
let result = b(data)
select new { a = (int)result.a, b = (int)result.b };
var average = sum_b != 0 ? sum_a / sum_b : 0;
对于其他结构,这很简单。
public struct Int_Int //May be a class or interface for mapping
{
public int a = 0, b = 0;
}
然后
int sum_a = 0,sum_b = 0;
Func<string[], Int_Int> b = (string[] data) => {
sum_a += int.Parse(data[0]);
sum_b += int.Parse(data[1]);
return new Int_Int() { a = int.Parse(data[0]), b = int.Parse(data[0]) };
};
var records = from line in fileLines
let data = line.Split(',')
select b(data);
var average = sum_b != 0 ? sum_a / sum_b : 0;
答案 5 :(得分:0)
SUM会在您调用它时获取所有记录,我建议您使用ToList() - &gt; Do you ToList()?
var records = from line in myfile
let data = line.Split(',')
select new { a=int.Parse(data[0]), b=int.Parse(data[1]) }.ToList();
var sumb = records.Sum(r => r.b);
var average = sumb !=0?records.Sum(r => r.a) / sumb :0;