.net - Der schnellste Weg, eine Sammlung von numerischen Werten zu summieren

stimmen
2

Ich habe eine Methode, die eine Sammlung von Dezimalzahlen fasst ein Verfahren ähnlich wie dies mit ...

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 

In dem eigentlichen Code gibt es in der Regel mehr Elemente in der Menge Sammlung, und es gibt mindestens 50 individuelle Menge Sammlungen, die in einer Gesamtoperation aufsummiert werden müssen.

Diese Neuberechnung der Gesamtmenge wird oft als (mindestens einmal, und dann noch einmal für jede Änderung Sammel Inhalts) und wird in Profilspuren als raubend zwischen 2-5% der gesamten Betriebszeit zeigt, auf. Ich bin auf der Suche, um zu sehen, ob jemand eine Idee hat, wie man diese Summenoperation zu beschleunigen, oder ob dies nur die schnellsten sein Gehen zu bekommen.

Caching ist in diesem Fall nicht realistisch, da die Mengen müssen neu berechnet werden.

**** EDIT ** Für Ravadre und Joel - Der Gesamtbetrag auf Klassenebene gespeichert (jede Menge Sammlung und Summe werden in einer Klasseninstanz enthalten sind)

Irgendwelche Ideen?

Veröffentlicht am 06/08/2009 um 14:58
quelle vom benutzer
In anderen Sprachen...                            


9 antworten

stimmen
3

Versuchen Subklassifizieren List (Of Decimal), setzen eine totalSum Eigenschaft. Jedes Mal, Add () wird, erhöht den insterted Wert bezeichnet. Das wird verhindern, dass Sie mit durch die Liste zu durchlaufen, die Summe zu erhalten.

Edit: Nach dem Versuch, es wäre besser, IList zu implementieren (Of Decimal), weil Liste Methoden nicht virtuell sein. Etwas nach dem Vorbild dieser (Ja, ich weiß, es ist C # ist ...)

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; }
    }
}
Beantwortet am 06/08/2009 um 15:11
quelle vom benutzer

stimmen
2

Wenn diese Währungswerte sind, sollten skaliert ganze Zahlen verwenden. Für 2 Dezimalstellen, speichern Sie die # Pfennige statt die Zahl der Dollar, dann durch 100 teilen, wenn Sie das Ergebnis auszugeben brauchen. Für 5 Dezimalstellen, Ihre Variablen intern verwenden, um die ursprüngliche Anzahl * 100000. Diese und die Performance und Genauigkeit verbessern sollten, vor allem, wenn Sie irgendeine Abteilung tun.

Beantwortet am 06/08/2009 um 18:11
quelle vom benutzer

stimmen
2

Es ist mir nicht klar, wie Sie erwarten, eine Liste von Zahlen zu addieren schneller als jedes wiederum addieren!

Jedoch unter Verwendung von decimals - Arithmetik zu tun , ist wahrscheinlich viel, viel, viel langsamer als ein Gleitkommatyp verwenden, wenn Sie also nicht wirklich tun müssen , um die Genauigkeit, schlage ich vor Umschaltung.

Beantwortet am 06/08/2009 um 15:05
quelle vom benutzer

stimmen
1

2-5% des gesamten Profilspur Es ist einfach nicht so viel.

Auch wenn Sie die Ausführungszeit dieses Verfahrens in zwei Hälften geschnitten, haben Sie höchstens ein paar Prozent der Gesamtlaufzeit gesichert.

Ihre beste Wette ist wahrscheinlich woanders zuerst hinschauen soll.

Beantwortet am 06/08/2009 um 15:11
quelle vom benutzer

stimmen
1

es gibt mindestens 50 individuelle Menge Sammlungen, die in einer Gesamtoperation aufsummiert werden müssen.

Was ist von jeder einzelnen Sammlung der Summen-Caching? Dann, wenn eine Sammlung verändert haben Sie nur diese Sammlung zu summieren und die zwischengespeicherten Summen.

Beantwortet am 06/08/2009 um 15:09
quelle vom benutzer

stimmen
1

Was ist totalAmount = amountCollection.Sum()?

Beantwortet am 06/08/2009 um 15:04
quelle vom benutzer

stimmen
0

Wenn Sie nicht über eine Version von IList / IDictionary implementieren wollen als statenjason vorgeschlagen könnten Sie einen Wrapper erstellen:

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
Beantwortet am 06/08/2009 um 16:35
quelle vom benutzer

stimmen
0

Ihre andere Alternative ist für Schleife, würden Sie nicht einen Enumerator erstellen müssen, aber praktisch gibt es keinen deutlichen Schub sowieso (soweit ich weiß).

Warum können Sie das Ergebnis nicht zwischenspeichern? Wenn Sie insgesamt ammount zwischenzuspeichern, und für jede Änderung eines Ihrer Elemente, ändern Menge den gleichen Wert verwenden (und berechnen schließlich jeweils alle 10 Änderungen für Synch). Also, wenn eines der Elemente von 2,5 bis 3,6 geändert wird, fügen Sie nur 1,1 auf Ihren Gesamtbetrag. Warum wird dies nicht in Ihrem Fall?

Beantwortet am 06/08/2009 um 15:05
quelle vom benutzer

stimmen
0

Das ist etwa so schnell wie es geht , um die Tatsache zu bekommen gegeben , dass Sie eine verwenden List(Of T).

Andere haben vorgeschlagen , dass Sie die Verwendung SumErweiterungsmethode - das wird nicht die Leistung verbessern , wie ihre Umsetzung , um Ihre aktuelle Lösung für das Problem identisch ist:

<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
Beantwortet am 06/08/2009 um 15:02
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more