varias valores valor una tabla sólo sumar suma separadas para dinamica cumplen configurar condición como columnas celdas campo acumulada .net collections sum

tabla - .Net-La forma más rápida de sumar una colección de valores numéricos



sumar valores en excel sólo si cumplen una condición (9)

hay al menos 50 colecciones de cantidades individuales que deben sumarse en una operación total.

¿Qué pasa con el almacenamiento en caché de las sumas de cada colección individual? Luego, cuando una colección cambia, solo tiene que resumir esa colección y los totales en caché.

Tengo un método que resume una colección de valores decimales usando un método similar a este ...

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

En el código real, generalmente hay más miembros en la colección de cantidades, y hay al menos 50 colecciones de cantidades individuales que deben sumarse en una operación total.

Este recálculo de la cantidad total se llama con frecuencia (al menos una vez, y luego otra vez por cada cambio de contenido de la colección), y se muestra en las huellas de perfil como consumir entre el 2-5% del tiempo de operación total. Estoy buscando ver si alguien tiene una idea de cómo acelerar esta operación de suma, o si esto es lo más rápido que va a obtener.

El almacenamiento en caché no es realista en este caso, porque las cantidades deben volver a calcularse.

**** EDIT ** Para Ravadre y Joel: la cantidad total se almacena en el nivel de la clase (cada colección de cantidad y suma se incluye en una instancia de clase)

¿Algunas ideas?


¡No tengo claro cómo esperas sumar una lista de números más rápido que agregar cada uno uno por vez!

Sin embargo, usar decimal para hacer aritmética es probablemente mucho, mucho, mucho más lento que usar un tipo de coma flotante, por lo que si no necesitas la precisión, sugiero cambiar.


¿Qué pasa con totalAmount = amountCollection.Sum() ?


El 2-5% del tiempo total de seguimiento de tu perfil simplemente no es mucho.

Incluso si reduce el tiempo de ejecución de este método a la mitad, habrá ahorrado como mucho un porcentaje de su tiempo de ejecución total.

Tu mejor opción es, probablemente, buscar en otro lugar primero.


Eso es lo más rápido posible dado que está usando una List(Of T) .

Otros han sugerido que use el método de extensión Sum ; esto no mejorará el rendimiento ya que su implementación es idéntica a su solución actual al problema:

<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


Intente subclasificar la lista (De decimal), exponer una propiedad TotalSum. Cada vez que se invoca Add (), incremente en el valor introducido. Eso te evitará tener que repetir la lista para obtener la suma.

Editar: Después de intentarlo, sería mejor implementar IList (Of Decimal) porque los métodos de List no son virtuales. Algo parecido a esto (sí, sé que es 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; } } }


Si no desea implementar una versión de IList / IDictionary como statenjason sugirió que podría crear un contenedor:

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


Si se trata de valores monetarios, considere el uso de enteros escalados. Para dos decimales, almacena el número de centavos en lugar del número de dólares, luego divida entre 100 cuando necesite dar salida al resultado. Para 5 decimales, sus variables usan internamente el número original * 100000. Esto debería mejorar tanto el rendimiento como la precisión, especialmente si está haciendo cualquier división.


Tu otra alternativa es usar for loop, no tendrías que crear un enumerador, pero prácticamente no hay ningún boost significativo de todos modos (hasta donde yo sé).

¿Por qué no puedes almacenar en caché el resultado? Si almacena en caché la cantidad total, y para cada cambio de uno de sus elementos, modifique la cantidad usando el mismo valor (y eventualmente calcule todas las 10 modificaciones para sincronizar). Entonces, cuando uno de los elementos cambia de 2.5 a 3.6, simplemente agrega 1.1 a su cantidad total. ¿Por qué esto no funcionará en tu caso?