.Net - 总结数值集合的最快方法

时间:2009-08-06 13:58:32

标签: .net collections sum

我有一个方法,使用类似于此的方法汇总一组十进制值...

Dim _amountCollection as New List(Of Decimal)
_amountCollection.Add(145.12D)
_amountCollection.Add(11.32D)
_amountCollection.Add(6547.07D)

Dim _totalAmount as Decimal

For Each _individualAmount as Decimal in _amountCollection
  _totalAmount += _individualAmount
Next 

在实际代码中,金额集合中通常有更多成员,并且至少有50个单独的金额集合需要在总操作中求和。

经常调用总量的重新计算(至少一次,然后再次针对每个集合内容更改),并且在配置文件跟踪中显示占总操作时间的2-5%。我希望看看是否有人知道如何加快这个求和操作,或者这是否是最快的。

在这种情况下缓存是不现实的,因为必须重新计算必须的金额。

****编辑** 对于Ravadre和Joel - 总金额存储在类级别(每个金额集合和总和都包含在类实例中)

有什么想法吗?

9 个答案:

答案 0 :(得分:3)

尝试继承List(Of Decimal),公开TotalSum属性。每次调用Add()时,都会按照插入的值递增。这将使您不必遍历列表以获得总和。

编辑: 尝试之后,最好实现IList(Of Decimal),因为List的方法不是虚拟的。有点像这样的(是的,我知道它是C#......)

public class DecimalSumList : IList<decimal>
{
    readonly IList<decimal> _allValues = new List<decimal>();
    decimal _totalSum;
    public decimal TotalSum { get { return _totalSum; } }
    public void Add(decimal item)
    {
        _totalSum += item;
        _allValues.Add(item);
    }

    public void CopyTo(decimal[] array, int arrayIndex)
    {
        _allValues.CopyTo(array, arrayIndex);
    }

    bool ICollection<decimal>.Remove(decimal item)
    {
        _totalSum -= item;
        return _allValues.Remove(item);
    }

    public int Count
    {
        get { return _allValues.Count; }
    }

    public bool IsReadOnly
    {
        get { throw new NotImplementedException(); }
    }

    public void Remove(decimal item)
    {
        _totalSum -= item;
        _allValues.Remove(item);
    }
    public void Clear()
    {
        _totalSum = 0;
        _allValues.Clear();
    }

    public bool Contains(decimal item)
    {
        return _allValues.Contains(item);
    }

    public IEnumerator<decimal> GetEnumerator()
    {
        return _allValues.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public int IndexOf(decimal item)
    {
        return _allValues.IndexOf(item);
    }

    public void Insert(int index, decimal item)
    {
        _totalSum += item;
        _allValues.Insert(index,item);
    }

    public void RemoveAt(int index)
    {
        _totalSum -= _allValues[index];
        _allValues.RemoveAt(index);
    }

    public decimal this[int index]
    {
        get { return _allValues[index]; }
        set { _allValues[index] = value; }
    }
}

答案 1 :(得分:2)

我不清楚您希望如何比依次添加每个数字更快地添加数字列表!

但是,使用decimal进行算术运算可能比使用浮点类型慢得多,所以如果你实际上不需要精度,我建议切换。

答案 2 :(得分:2)

如果这些是货币值,请考虑使用缩放整数。 对于2位小数,您存储的是便士数而不是美元数,然后在需要输出结果时除以100。 对于5位小数,您的变量在内部使用原始数字* 100000。 这应该会提高性能和准确性,尤其是在进行任何划分时。

答案 3 :(得分:1)

totalAmount = amountCollection.Sum()怎么样?

答案 4 :(得分:1)

  

至少有50个单独的金额集合需要在总操作中求和。

如何缓存每个系列的总和?然后,当集合发生变化时,您只需要总结该集合和缓存的总计。

答案 5 :(得分:1)

总分析跟踪时间的2-5%并不是那么多。

即使您将此方法的执行时间缩短了一半,您最多也可以节省总运行时间的百分之几。

你最好的选择可能是先到别处去看看。

答案 6 :(得分:0)

考虑到你使用的是List(Of T),事情的速度和它一样快。

其他人建议您使用Sum扩展方法 - 这将提高性能,因为其实现与您当前解决问题的方法相同:

<Extension> _
Public Shared Function Sum(ByVal source As IEnumerable(Of Decimal)) As Decimal
    If (source Is Nothing) Then
        Throw Error.ArgumentNull("source")
    End If
    Dim num As Decimal = 0
    Dim num2 As Decimal
    For Each num2 In source
        num = (num + num2)
    Next
    Return num
End Function

答案 7 :(得分:0)

你的另一种选择是使用for循环,你不必创建一个枚举器,但实际上并没有显着的提升(据我所知)。

为什么你不能缓存结果?如果缓存总数量,并且对于其中一个元素的每次更改,请使用相同的值修改数量(并最终计算所有每个10个修改以进行同步)。因此,当其中一个元素从2.5更改为3.6时,您只需将1.1添加到总金额中。为什么这不适用于您的情况?

答案 8 :(得分:0)

如果你不想实现IList / IDictionary的版本,因为statenjason建议你可以创建一个包装器:

Public Class TotalDictionaryWrapper
        Private innerDictionary As IDictionary(Of Integer, Decimal)
        Private m_total As Decimal = 0D
        
        Public Sub New(ByVal dictionary As IDictionary(Of Integer, Decimal))
            Me.innerDictionary = dictionary
        End Sub
        
        Public ReadOnly Property Total() As [Decimal]
            Get
                Return Me.m_total
            End Get
        End Property
        
        Public Sub Add(ByVal key As Integer, ByVal value As Decimal)
            Me.innerDictionary.Add(key, value)
            m_total += value
        End Sub
        
        Public Sub Remove(ByVal key As String)
            Dim toRemove As Decimal = Me.innerDictionary(key)
            Me.innerDictionary.Remove(key)
            Me.m_total -= toRemove
        End Sub
        
        Public Sub Update(ByVal key As Integer, ByVal newValue As Decimal)
            Dim oldValue As Decimal = Me.innerDictionary(key)
            Me.innerDictionary(key) = newValue
            Me.m_total -= oldValue
            Me.m_total += newValue
        End Sub
        
        Other methods..

    End Class