类
public class myItem
{
public int ID;
public long Value;
public long Sum1;
public long Sum2;
public long Sum3;
}
数据
ID Value
1 25
2 45
3 56
4 21
结果:
Sum1 Sum2 Sum3
1 25 25 + 45 25 + 45 + 56
2 45 45 + 56 45 + 56 + 21
3 56 56 + 21 56 + 21 + 0
4 21 21 + 0 21 + 0 + 0
当前程序:工作但很慢(约10分钟),行数为100k。
List<myItem> list;
for (int i = 0; i < list.Count(); i++)
{
myItem m = list[i];
m.Sum1 = list.Where(x => x.ID == i).Sum(x => x.Value);
m.Sum2 = list.Where(x => x.ID >= i && x.ID <= i + 2).Sum(x => x.Value);
m.Sum3 = list.Where(x => x.ID >= i && x.ID <= i + 3).Sum(x => x.Value);
}
所以我想应该有办法在没有for
的情况下加快速度。
答案 0 :(得分:5)
缓慢的根本原因是你的循环是O(n ^ 2),因为对于每个元素,你搜索整个列表的后继。下面将其减少到O(n log n)(最慢的部分是排序)。
List<myItem> list;
list.Sort(<.. sort by id ..>);
for (int i = 0; i < list.Count; i++)
{
myItem m = list[i];
m.Sum1 = m.Value;
m.Sum2 = m.Sum1;
if (i < list.Count - 1)
{
m.Sum2 += list[i + 1].Value;
}
m.Sum3 = m.Sum2;
if (i < list.Count - 2)
{
m.Sum3 = += list[i + 2].Value;
}
}
答案 1 :(得分:2)
(取消删除答案,因为事实证明其他答案仍有微妙的错误)
LINQ对此没有帮助。只需根据需要引用数组索引:
List<myItem> list;
// sort list by id
list.Sort(t => t.ID);
for (int i = 0; i < list.Count; i++)
{
myItem m = list[i];
m.Sum1 = m.Value;
m.Sum2 = m.Sum1 + (i + 1 < list.Count ? list[i + 1].Value : 0);
m.Sum3 = m.Sum2 + (i + 2 < list.Count ? list[i + 2].Value : 0);
}
编辑:关于list.Count()vs list.Count的小注释
我注意到有关于不使用list.Count()
(Enumerable.Count()
)赞成list.Count
(属性)的评论。我个人也喜欢这样,但应该注意的是,不像有些人可能会相信,Enumerable.Count()
版本不会迭代整个列表以获得计数。相反,因为它检测到列表是ICollection<T>
的实现,所以它将直接使用Count
属性。实际上,在这个特定情况下 这两个选项之间的性能差异可以忽略不计。
此行为记录在案here。
如果 source 的类型实现
ICollection<T>
,则该实现用于获取元素的数量。否则,此方法确定计数。
答案 2 :(得分:2)
只是对Jared的解决方案进行了一些修改,但是使用了他的想法:
List<myItem> list;
//list.Sort(<.. sort by id ..>);
int count = list.Count();
for (int i = 0; i < count; i++)
{
myItem m = list[i];
m.Sum1 = m.Value;
m.Sum2 = (i+1 < count) ? (m.Value + list[i+1].Value) : m.Value;
m.Sum3 = (i+2 < count) ? (m.Sum2 + list[i+2].Value) : m.Sum2;
}
答案 3 :(得分:0)
另一种解决方案。不需要排序。不确定它是否会运行得更快,请检查。
list.ForEach(m =>
{
m.Sum1 = m.Value;
m.Sum2 = ((m.ID + 1) < list.Count) ? (m.Sum1 + list[m.ID + 1].Value) : m.Sum1;
m.Sum3 = ((m.ID + 2) < list.Count) ? (m.Sum2 + list[m.ID + 2].Value) : m.Sum2;
});