2016-07-23 9 views
1

enter image description hereArray Formel in reguläre

Hallo alle, durch eine Anordnung Formeln (in dem obigen Beispiel) zu berechnen:

Count einzigartige Kunden, die nur weniger als 5 Einheiten nur Produkt 1 gekauft hat, die Ortsvorwahl Übereinstimmung nur mit den benachbarten Zellen D

I die folgende Matrixformel Anwendung bei E11 sein:

=SUM(IF(FREQUENCY(IF($G$2:$G$7=D11, 
    IF($I$2:$I$7="Product 1",IF($J$2:$J$7<5,IF($E$2:$E$7<>"", 
    MATCH($E$2:$E$7,$E$2:$E$7,0))))),ROW($E$2:$E$7)-ROW(G2)+1),1)) 

diese formu Ich mache es großartig, zur gleichen Zeit, wenn es durch sehr riesige Datenbank mit Tonnen von Reihen und Spalten verwendet, dauert Excel etwa 3 Minuten, um nur eine Zelle zu berechnen, die schrecklich ist, so weiterzugehen

gibt es einen Weg, um zu konvertieren Diese Array-Formel zu regelmäßigen one ... jede Hilfe wird bis zum Maximum geschätzt ... Vielen Dank im Voraus

+0

vba wird Ihre beste Wette. Meine Vermutung, ohne zu sehr darauf einzugehen, werden Sie nicht in der Lage sein, Array-Formeln zu umgehen. –

+0

Vielen Dank für Ihren Hinweis, zur gleichen Zeit macht mir nichts dagegen, VBA zu verwenden, aber ich weiß nicht, um solche Formel in VBA-Code zu konvertieren :) .... Ich werde alles tun, um all diese vergeudeten Stunden zu vermeiden, auf Excel zu warten Berechnen Sie solche Formeln :) –

+2

Stack Overflow ist keine "Code für mich", "Teach me to code" oder "Finde mich Code" -Site. –

Antwort

0

Entschuldigung für die späte Antwort.

Ich habe eine UDF erstellt, die sich darauf konzentriert, die Berechnung mehrmals durchzuführen, ohne den gesamten Bereich mehrmals zu durchlaufen.

Public Function getCounts(AreaStr As Variant, AreaRng As Range, CustomerRng As Range, ProductRng As Range, SalesRng As Range, Optional ProductName As String = "Product 1", Optional lessThan As Double = 5) As Variant 

    'make sure AreaStr is an array 
    If TypeOf AreaStr Is Range Then AreaStr = AreaStr.Value2 
    If Not IsArray(AreaStr) Then 
    AreaStr = Array(AreaStr) 
    ReDim Preserve AreaStr(1 To 1) 
    End If 

    'shorten the range (this way you can use whole columns) 
    If SalesRng(SalesRng.Cells.Count).Formula = "" Then Set SalesRng = SalesRng.Parent.Range(SalesRng.Cells(1), SalesRng(SalesRng.Cells.Count).End(xlUp)) 

    'make sure all ranges have the same size 
    Set AreaRng = AreaRng.Resize(SalesRng.Rows.Count) 
    Set CustomerRng = CustomerRng.Resize(SalesRng.Rows.Count) 
    Set ProductRng = ProductRng.Resize(SalesRng.Rows.Count) 

    'Load values in variables to increase speed 
    Dim SalesValues As Variant, UserValues As Variant, ProductValues As Variant 
    SalesValues = AreaRng 
    UserValues = CustomerRng 
    ProductValues = ProductRng 

    'create temporary arrays to hold the values 
    Dim buffer() As Variant, expList() As Variant 
    ReDim buffer(1 To UBound(UserValues)) 
    ReDim expList(1 To UBound(AreaStr), 1 To 1) 

    Dim i As Long, j As Double, k As Long 
    For i = 1 To UBound(AreaStr) 
    expList(i, 1) = buffer 
    Next 

    buffer = Array(buffer, buffer) 
    buffer(0)(1) = 0 

    For i = 1 To UBound(UserValues) 
    If ProductValues(i, 1) = ProductName Then 'this customer purchased our product 
     j = Application.IfError(Application.Match(UserValues(i, 1), buffer(0), 0), 0) 
     If j = 0 Then 'first time this customer in this calculation 
     j = i 
     buffer(0)(j) = UserValues(i, 1) 'remember the customer name (to not calculate him again later) 
     If Application.SumIfs(SalesRng, CustomerRng, UserValues(i, 1), ProductRng, ProductName) < lessThan Then 
      buffer(1)(j) = 1 'customer got less than "lessThan" -> remember that 
     End If 
     End If 
     If buffer(1)(j) = 1 Then 'check if we need to count the customer 
     k = Application.IfError(Application.Match(SalesValues(i, 1), AreaStr, 0), 0) 'check if the area is one of the areas we are looking for 
     If k Then expList(k, 1)(j) = 1 'it is -> set 1 for this customer/area combo 
     End If 
    End If 
    Next 

    For i = 1 To UBound(AreaStr) 'sum each area 
    expList(i, 1) = Application.Sum(expList(i, 1)) 
    Next 

    getCounts = expList 'output array 

End Function 

Ich nehme an, dass Sie es als eine UDF ohne meine Hilfe aufnehmen können.

Im Blatt, das Sie (für Beispiel) E11 verwenden würden:

E16
=getCounts(D11:D15,G2:G7,E2:E7,I2:I7,J2:J7) 

wählen Sie einfach den Bereich von E11: E16 und geben Sie die Formel, es dann mit CSE bestätigen.

können Sie auch nur =getCounts(D11,$G$2:$G$7,$E$2:$E$7,$I$2:$I$7,$J$2:$J$7) bei E11 verwenden und dann nach unten kopieren ... aber das wäre ziemlich langsam.

Der Trick ist, dass wir die Summe des Sets für jeden Kunden berechnen, der es mindestens einmal gekauft hat. Dann speichern wir 1, wenn es weniger als Ihre Kriterien ist. Dies gilt für das allgemeine Array. Jeder Bereich, den Sie suchen, wird auch ein eigenes Array bekommen. Hier lagern wir auch die 1 auf der gleichen Position. Da jeder Kunde nur einmal berechnet wird, spielt es keine Rolle, ob er ihn mehrere Male hat.

getCounts(AreaStr,AreaRng,CustomerRng,ProductRng,SalesRng,[ProductName],[lessThan]) 
  • AreaStr:

    einfach wird die Formel wie folgt verwendet werden, um die Ortsvorwahl die Sie suchen.sollte ein Array von mehreren Zellen, die UDF lohnt sich der Einsatz es

  • AreaRng zu machen: der Bereich, in dem die Bereichsnamen
  • CustomerRng gespeichert sind: der Bereich, wo die Kundennamen
  • ProductRng gespeichert sind: der Bereich, in dem das Produkt Namen werden gespeichert
  • SalesRng: der Bereich, in dem die Verkaufszahlen gespeichert werden
  • ProductName (optional): das Produkt, das Sie suchen. Wird "Produkt 1", wenn
  • weggelassen lessThan (optional): der Triggerpunkt für die Summe der Produkte. Wird 5 sein omited wenn

Die meisten Teile selbst sein sollte, zu erklären, aber wenn Sie noch Fragen haben, fragen Sie einfach;)

+0

Lieber Dirk, es funktioniert einwandfrei Vielen Dank für Ihren kooperativen Geist, Entschuldigung für mein spätes Feedback, aber ich habe versucht, jeden Teil davon zu verstehen, bevor ich ihn anwende, es funktioniert perfekt für das vorherige Beispiel, gleichzeitig, wenn ich Änderungen vornehmen möchte Meine Datenbereiche wie Array-Länge oder Spaltenname (z. B. Produkt in Markenname oder Area-Code zu Area-ID), dies wird jede Sache in meiner UDF ändern oder nicht, wenn ja welche Teile ich ändern werde, wenn ich meine Spaltenüberschriften ändere Namen oder Ergebniszellen? ..... Auf den MAX geschätzt. Danke +++++ :) –

+0

Es ist OK, ich habe es getan und ändern, was geändert werden muss, jetzt möchte ich eine andere Spalte zählen die gleichen Bedingungen, aber zählen Kunden gekauft mehr als 5, wie die erste UDF funktioniert für bestimmte Bereich und andere UDF um für verschiedene Bereiche auf dem gleichen Blatt zu arbeiten ?, das ist die Herausforderung jetzt :) –

+0

Um das Gegenteil zu tun, müsste man ein paar Anpassungen machen ... Ich werde das untersuchen, wenn ich wieder zu Hause bin ... –

0

OK, ich bin nicht sicher, ob ich alle Bedingungen und Anhäufung verstanden habe, aber hier ist eine VBA-Funktion Ich denke, sollte es tun.

Zuerst öffnen Sie VBA aus dem Menü Excel-Entwickler. Erstellen Sie dann in VBA ein neues Modul aus dem Menü Einfügen (lassen Sie es einfach Module1 sein). Fügen Sie dann die folgenden 2 Funktionen in das VBA-Modul ein.

Public Function AreaUniqueCustomersLessThan(ReportAreaRange, AreaRange, ProductRange, SalesRange, CustomerRange) 
    On Error GoTo Err1 
    Dim RptAreas() As Variant 
    Dim Areas() As Variant, Products() As Variant, Sales() As Variant, Customers As Variant 

    RptAreas = ArrayFromRange(ReportAreaRange) 

    Areas = ArrayFromRange(AreaRange) 
    Products = ArrayFromRange(ProductRange) 
    Sales = ArrayFromRange(SalesRange) 
    Customers = ArrayFromRange(CustomerRange) 

    Dim r As Long, s As Long 'report and source rows indexes 
    Dim mxr As Long, mxs As Long 
    mxr = UBound(RptAreas, 1) 
    mxs = UBound(Areas, 1) 


    'encode the ReportAreasList into accumulation array indexes 
    Dim AreaCustomers() As Collection 
    Dim i As Long, j As Long 
    Dim colAreas As New Collection 

    ReDim AreaCustomers(1 To mxr) 
    For r = 1 To mxr 
     On Error Resume Next 
      'Do we have the area already? 
      j = colAreas(RptAreas(r, 1)) 
     If Err.Number <> 0 Then 
      'Add a new area to the collection and array 
      i = i + 1 
      colAreas.Add i, RptAreas(r, 1) 
      Set AreaCustomers(i) = New Collection 
      j = i 
     End If 
    Next r 

    'now scan the source rows, accumulating distinct customers 
    ' for any ReportAreas 
    For s = 1 To mxs 
     'is this row's Arera in the report Area list? 
     i = 0 
     On Error Resume Next 
      i = colAreas(Areas(s, 1)) 
     On Error GoTo Err1 
     If i > 0 Then 

      'this is a report Area code, so check the conditions 
      If Products(s, 1) = "Product 1" Then 
       If Sales(s, 1) < 5 Then 

        On Error Resume Next 'just ignore any duplicate errors 
         AreaCustomers(i).Add Customers(s, 1), Customers(s, 1) 
        On Error GoTo Err1 

       End If 
      End If 

     End If 
    Next s 

    'finally, return to the report area codes, returning the distinct count 
    ' of customers 
    Dim count() As Variant 
    ReDim count(1 To mxr, 1 To 1) 
    For r = 1 To mxr 
     count(r, 1) = AreaCustomers(colAreas(RptAreas(r, 1))).count 
    Next r 

    AreaUniqueCustomersLessThan = count ' "foo" 
    Exit Function 

Err1: 
    AreaUniqueCustomersLessThan = "%ERR(" & Str(Err.Number) & ")%" & Err.Description 
    Exit Function 
    Resume 

End Function 


'handle all of the cases, checking and conversions to convert 
' a variant range into an array of Variant(1 to n, 1 to 1) 
' (we do this because it makes data access very fast) 
Function ArrayFromRange(varRange As Variant) 
    Dim rng As Range 
    Dim A() As Variant 

    Set rng = varRange 

    'Check for degenerate cases 
    If rng Is Nothing Then 
     'do nothing 
    ElseIf rng.count = 0 Then 
     'do nothing 

    ElseIf rng.count = 1 Then 
     ReDim A(1 To 1, 1 To 1) 
     A(1, 1) = rng.Value 

    Else 
     A = rng.Value 
    End If 

    ArrayFromRange = A 
End Function 

Schließlich gehen Sie zu Ihrem Array Formel Bereich und fügen Sie in der folgenden Matrixformel für die „Sales < 5“ -Liste: {=AreaUniqueCustomersLessThan(D$11:D$16, G$2:G$7, I$2:I$7,J$2:J$7,E$2:E$7)} Beachten Sie, dass der erste Bereich sich die gleiche Länge wie die Array-Formel-Bereich sein muss. Und die anderen vier Bereiche (die Quelldatenbereiche) sollten alle die gleiche Länge haben (sie müssen nicht die gleiche Länge wie der erste Bereich haben).