Vb.net 如何将性能良好的连续整数集合相加

Vb.net 如何将性能良好的连续整数集合相加,vb.net,performance,linq,Vb.net,Performance,Linq,我得到了一个IEnumerable(Of Integer)并希望将每组连续的三个整数相加,从第一个整数开始,最后一个整数减去两 示例:我的整数是{0,6,2,8,2,0,3,7,1}。我想把它转换成{0+60+2600+20+8,200+80+2,…}={62628,282,820,203,37,371},然后存储在一个排序集。请注意,我选择基数10是为了简化问题,实际上基数是不同的(集合中的最大值加1,因此我的方法将为集合中三个数字的每个排列生成唯一的ID) 我已经测试了三段不同的代码: (一

我得到了一个
IEnumerable(Of Integer)
并希望将每组连续的三个整数相加,从第一个整数开始,最后一个整数减去两

示例:我的整数是
{0,6,2,8,2,0,3,7,1}
。我想把它转换成
{0+60+2600+20+8,200+80+2,…}={62628,282,820,203,37,371}
,然后存储在一个排序集。请注意,我选择基数10是为了简化问题,实际上基数是不同的(集合中的最大值加1,因此我的方法将为集合中三个数字的每个排列生成唯一的ID)

我已经测试了三段不同的代码:

(一)

(二)

(三)

这三种方法都有效,但我对大约62k个整数集的测试表明,执行时间存在显著差异:方法1:1.8-2秒,方法2:1.4-1.5秒,方法3:0.75-0.77秒


由于性能对我的项目至关重要,我仍然不确定这是否是实现我想要的最好的代码。有人还有其他想法可以让我测试吗?

您第一次和第二次尝试的问题都与VB.NET有关,这是一种解决
IEnumerable(of T)
上类似数组的索引器访问的方法。这类调用被转换为
ElementAtOrDefault()
扩展方法调用,因此第一个方法如下所示:

For i = 0 To integers.Count - 3
  sums.Add(integers.ElementAtOrDefault(i) * 100 + integers.ElementAtOrDefault(i + 1) * 10 + integers.ElementAtOrDefault(i + 2))
Next
是的,
ElementAtOrDefault()
每次调用它时,可能需要从集合的开头开始迭代(取决于实际的
IEnumerable(of T)
实现)。所以,在更糟糕的情况下,您的解决方案反复迭代您的集合,而您甚至不知道这一点

这也是为什么
Zip
让它变得更好的原因。它只在源集合上迭代3次,这比前面描述的情况要好得多

另一种可能的解决方案

您可以尝试使用
聚合

Dim sums = New SortedSet(Of Integer)()
source.Aggregate(
    New List(Of Integer)(3),
    Function(l As List(Of Integer), i As Integer)
        l.Add(i)
        If l.Count = 3 Then
            sums.Add(l(0) * 100 + l(1) * 10 + l(2))
            l.RemoveAt(0)
        End If
        Return l
    End Function,
    Function(l) l)

是的,我使用了索引器访问语法,但是因为它在helper
List(Of T)
上,所以它实际上是一个索引器访问,而不是隐藏的
IEnumerable.ElementAtOrDefault(index)
调用。

我想我还是使用邮政编码(hee-hee),它比聚合版本更容易理解。感谢您解释运行时差异的原因。同时,我了解LINQ的内部实现,因为我看过一些类似LINQ的扩展的源代码。现在我明白了代码背后发生了什么,以及为什么运行时差异如此之大。
Dim num = integers.Count - 2
Dim intsX = integers.Take(num)
Dim intsY = integers.Skip(1).Take(num)
Dim intsZ = integers.Skip(2)
sums = New SortedSet(Of Integer)(
  intsX.Zip(
  intsY, Function(x, y) x * 100 + y * 10).Zip(
  intsZ, Function(xy, z) xy + z)
)
For i = 0 To integers.Count - 3
  sums.Add(integers.ElementAtOrDefault(i) * 100 + integers.ElementAtOrDefault(i + 1) * 10 + integers.ElementAtOrDefault(i + 2))
Next
Dim sums = New SortedSet(Of Integer)()
source.Aggregate(
    New List(Of Integer)(3),
    Function(l As List(Of Integer), i As Integer)
        l.Add(i)
        If l.Count = 3 Then
            sums.Add(l(0) * 100 + l(1) * 10 + l(2))
            l.RemoveAt(0)
        End If
        Return l
    End Function,
    Function(l) l)