我有以下列表:
List<Decimal?> values = new List<Decimal?> { 3, null, 2, 1, 4, 3 };
我需要创建一个新列表,其中包含每个项目与前两个项目之间的最大值,因此:
List<Decimal?> maximums = new List<Decimal?> { 3, 2, 4, 4 };
3 = Maximum of { 3, null, 2 }
2 = Maximum of { null, 2, 1 }
4 = Maximum of { 2, 1, 4 }
4 = Maximum of { 1, 4, 3 }
我的想法是有一个循环,并在每次迭代中执行:
for (int i = 2; i < values.Count(); i++) {
Decimal? maximum = values.Skip(i).Take(3).Max();
maximums.Add(maximum);
}
有没有办法只使用 Linq 来做到这一点?
答案 0 :(得分:4)
我不确定您和其他答案为什么会先执行 Skip(2)
。根据 3,2,4,4
的输入所需的 3,null,2,1,4,3
输出,您不会得到正确的结果。如果你真的想跳过2,那么修改下面的代码。
您要查找的内容通常被认为是 sliding window。
如果你同意它,有一个 Morelinq 方法被适当地调用,Window() 将产生一个序列序列,每个序列的长度都需要。
您可以像这样将其应用于您的问题
var values = new List<decimal?> { 3, null, 2, 1, 4, 3 };
var maximums = values.Window(3).Select(x => x.Max()).ToList();
对于长度不超过 3 的每个子序列,我们选择最大值。这会产生您想要的结果:3,2,4,4
。
Window()
方法缓冲每个序列,但整体流式传输结果。没有使用 Skip()
,因此您不会陷入将源扫描到每个索引的陷阱,从而提高效率。
如果你不想下载包,你可以自己滚动,而不是产生窗口序列,直接从缓冲序列中产生最大值。
答案 1 :(得分:0)
当然 - 只需使用 Skip(2)
来模拟您的循环:
values.Skip(2).Select((x,i) => values.Skip(i).Take(3).Max())