2016-05-13 9 views
1

I gelesen derzeit einen 2-dimensionalen Bereich in ein Array Excel VBA etwa so:Zählzahl der nicht-leeren Felder in Excel VB Array Säule

Set Ws = Sheet1 
Ws.Activate 

LastRow = Ws.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row 
LastCol = Ws.Cells.Find("*", searchorder:=xlByColumns, searchdirection:=xlPrevious).Column 

ReDim elements(0 To LastRow - 2, 0 To LastCol - 2) 
elements = Ws.Range(Cells(2, 1), Cells(LastRow, LastCol)) 

Bereich von 25 Zeilen mal 11 Spalten ist. Allerdings haben nicht alle Zellen im Bereich Werte, sodass einige der Werte im Array "leer" sind.

  • col A hat 25 Elemente
  • col B hat 16
  • col K 12 hat ...

Ich muss durch diese Anordnung eine Schleife und ein zweites Array erstellen, wird die a "Kartesisches Produkt" der Werte von der ersten. Um zu bestimmen, wie oft ich eine Schleife machen muss, muss ich herausfinden, wie viele Elemente es in jeder der Array-Spalten gibt ("Dimensionen"?). Hier

ist ein Versuch, meine Schleife:

Row = 0 

For i = 1 To 25 'numElements in column 1 
For j = 1 To 3 'numElements in column 6   
    For k = 1 To 5 'numElements in column 7 
    For l = 1 To 14 'numElements in column 8 
    For m = 1 To 6  'numElements in column 10 
    For n = 1 To 12  'numElements in column 11 

     cartesian(Row, 0) = elements(i, 0) 
     cartesian(Row, 1) = elements(i, 1) 
     cartesian(Row, 2) = elements(i, 2) 
     cartesian(Row, 3) = elements(i, 3) 
     cartesian(Row, 4) = elements(i, 4) 
     cartesian(Row, 5) = elements(j, 5) 
     cartesian(Row, 6) = elements(k, 6) 
     cartesian(Row, 7) = elements(l, 7) 
     cartesian(Row, 8) = elements(l, 8) 
     cartesian(Row, 9) = elements(m, 9) 
     cartesian(Row, 10) = elements(n, 10) 

     Row = Row + 1 
    Next n   
    Next m 
    Next l 
    Next k 
Next j 
Next i 

Jede Hilfe dankbar :)

EDIT 1:

Dies ist der Bereich, den ich in array1 lesen:

Austria sem jan 
Belgium gdn feb 
France  mar 
US   apr 
       may 
       jun 

Ich muss zählen können wie viele " Artikel "gibt es in Spalte 1, Spalte 2 und Spalte 3, um sie zu multiplizieren. Auf diese Weise werde ich wissen, wie groß ich zum zweiten Array ReDim brauche.

Dies ist, was ich in dem Array muß 2 und schließlich wieder in ein anderes Blatt schreiben:

Austria sem jan 
Austria sem feb 
Austria sem mar 
Austria sem apr 
Austria sem may 
Austria sem jun 
Austria gdn jan 
Austria gdn feb 
Austria gdn mar 
Austria gdn apr 
Austria gdn may 
Austria gdn jun 
Belgium sem jan 
Belgium sem feb 
Belgium sem mar 
Belgium sem apr 
Belgium sem may 
Belgium sem jun 
Belgium gdn jan 
Belgium gdn feb 
Belgium gdn mar 
Belgium gdn apr 
Belgium gdn may 
Belgium gdn jun 

usw.

+0

Ich denke, das kann es überdenken. Was ist Ihr Ziel, nur die Zellen zu finden, die leer sind, in einer Reihe? Also, für die Spalten 1, 6, 7, 8, 10 und 11 wollen Sie die leeren Zellen finden? – BruceWayne

+1

Oder Alex möchte nur die "nicht leeren" Werte der Spalten 2 bis 11 mit den Werten der Spalte 1 kombinieren? – Kellsens

+0

Ich verstehe es auch nicht ... geht nach * kartesischem Produkt *, aber es gibt keine Berechnungen ... es ist nur eine Kopie des ersten Bereichs (nur die Werte werden gemischt). Also, wozu sind die verschiedenen Sets? jede Reihe? aber n sets liefert auch eine n-dimensionale Ausgabe ... Ich bin verwirrt:/ –

Antwort

1

Dies sollte es tun, wie Sie es in einem angemessenen Betrag von Zeit benötigen. .. wird noch einige Zeit für ~ 300k Einträge nehmen:

Option Explicit 

Sub getMyList() 

    'set input 
    Dim inputVal As Variant 

    'get input values 
    With ThisWorkbook.Worksheets("Sheet1") 
    inputVal = .Range(.Cells(1, 1), .Cells(.Cells.Find("*", , , , 1, 2).Row, .Cells(1, 1).End(xlToRight).Column)).Value 
    End With 

    'set count array 
    Dim xCounts() As Variant 
    ReDim xCounts(1 To UBound(inputVal, 2)) 

    Dim i As Long, j As Long 
    For i = 1 To UBound(xCounts) 
    j = 1 
    While inputVal(j, i) <> "" And j < UBound(inputVal) 
     j = j + 1 
    Wend 
    'xCounts(i) = j - 1 'will skip last value if it is at the last row 
    xCounts(i) = j + (inputVal(j, i) = "") 'new one will work as wanted 
    Next 

    'set output sizes 
    Dim outVal() As Variant 
    ReDim outVal(1 To Application.Product(xCounts), 1 To UBound(xCounts)) 

    'runner sets 
    Dim colRunner As Long, rowRunner As Long, copyRunner As Long 
    Dim itemRep As Long, listRep As Long 

    For colRunner = 1 To UBound(xCounts) 

    rowRunner = 1 
    itemRep = 1 
    listRep = 1 

    'repeat whole list 
    For i = 1 To colRunner - 1 
     listRep = listRep * xCounts(i) 
    Next 

    'repeat each item 
    For i = colRunner + 1 To UBound(xCounts) 
     itemRep = itemRep * xCounts(i) 
    Next 

    'run the list for output 
    copyRunner = 1 
    For i = 1 To listRep 
     For copyRunner = 1 To xCounts(colRunner) 
     For j = 1 To itemRep 

      outVal(rowRunner, colRunner) = inputVal(copyRunner, colRunner) 
      rowRunner = rowRunner + 1 

     Next 
     Next 
    Next 
    Next 

    'output everything 
    ThisWorkbook.Worksheets("Sheet2").Cells(1, 1).Resize(UBound(outVal), UBound(outVal, 2)).Value = outVal 

End Sub 

Der Code sollte einfach zu lesen (es gibt keine wirkliche Magie innen): P

Wenn jedoch Fragen offen sind, fragen Sie einfach :)

EDIT

Die xCounter einfach die Zählungen aller Elemente für jede Spalte halten, weil diese Zahlen viele Male verwendet werden.
Zur Klarstellung: Lassen Sie uns annehmen, dass Sie eine Liste wie folgt aus:

A B C D E 
1 1 1 1 1 
2 2 2 2 2 
3 3 3 3 
4 4 4 
5 5 5 
6 6 6 
7  7 
8 

(Gebraucht Zahlen für die einfache Zählen, funktioniert auch mit beliebigen Strings)
XCounter jetzt {8,2,6,7,3} sein wird. Wenn Sie jetzt die Spalte C aufschreiben möchten, müssen Sie wissen, wie oft jedes Element wiederholt werden muss. Dies kann berechnet werden, indem die Zählungen aller Spalten multipliziert werden, die später kommen. Für diesen Fall wäre es 7 * 3 = 21 mal.Außerdem müssen Sie wissen, wie viele Elemente in der Liste durchlaufen werden, die 6 sein wird. Dann muss die ganze Liste sich auch wiederholen, was durch Multiplizieren aller Zählungen von Zeilen, die davor liegen, berechnet werden kann. Das wäre 8 * 2 = 16 mal. Auf diese Weise werden auch die 3 inneren For ... Next Loops aufgebaut. ListRepeat(EachItem(ItemRepeat)). Um zu wissen, welche Zeile im Ausgabe-Array geschrieben werden soll, benötigen Sie einen einfachen Aufwärtszählwert, der RowCounter ist. Wenn Sie dies direkt in das Blatt tun, würden Sie einen Bereich verwenden, der jedes Mal, wenn ein Wert in eine Zelle geschrieben wird, einfach um eine Zeile nach unten versetzt.
Durch dieses System machen Sie jede Spalte komplett getrennt von den anderen, weil alles, was Sie benötigen, sind die Produkte der Artikel zählt der führenden und folgenden Spalten (für die wir xCounter haben). Trotzdem müssen wir dies für jede Spalte tun, also ist die äußere Schleife die Spalte (colRunner).
Einfach für nicht durch 4 Schleifen mit i, j, k, l ineinander verwirren Ich habe den "Läufer" für die Zeilen in outVal zu rowRunner und die für die Spalten zu colRunner umbenannt. Da die oberen und unteren Grenzen für die Wiederholungen direkt vor den inneren Schleifen liegen, blieb ich bei i und j. (Sie werden auch nicht für irgendetwas in diesen Schleifen verwendet, sie stellen einfach die Wiederholungen sicher, indem sie die gleiche Aktion mehrmals ausführen)

Wenn ich etwas übersehen habe oder andere Fragen auftauchen, tun Sie es einfach so, wie es immer das Richtige ist tu: frag. ;)

+0

Ich mag die Art, wie du das gemacht hast (ich dachte an einen anderen Weg, aber wahrscheinlich nicht so gut). Eine Sache, die mir aufgefallen ist, ist, dass 'jun' in der letzten Spalte übersprungen wird - suggerate something For j = 1 An UBound (inputVal) Wenn inputVal (j, i) = "" Dann Exit für Weiter j im Set-Count-Array-Code. –

+1

@TomSharpe änderte 'xCounts (i) = j - 1' in' xCounts (i) = j + (inputVal (j, i) = "") ''. sollte jetzt funktionieren :) –

+0

Dirk, DANKE für die große Anstrengung, die ich wirklich schätze! Hier [link] (http://jsfiddle.net/astrbac/vj1atc82) habe ich es ein wenig an meinen Stil "angepasst" (Deklarationen an der Spitze). Ich habe jedoch ein bisschen mit Verständnis zu kämpfen: Sie erstellen zunächst eine Reihe von Elementen zu kombinieren. Am Ende erstellen Sie ein Array, um auf das Blatt zurück zu schreiben. Ich verstehe jedoch nicht, whz das xCount-Array und was macht der rowRunner und colRunner tun? Vielen Dank für Klarstellungen im Voraus! –