Vorhandenes Programm ins Array umschreiben

  • Excel

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von Parawolli.

    Vorhandenes Programm ins Array umschreiben

    In der Angehängten Datei habe ich mit Sub Status_1 ein Programm geschrieben, was die SN: Nr. aus Spalte F & den Status Spalte I vom Blatt "geplante Analysatoren (2)" ins Blatt "geplante Analysatoren" überträgt.
    Und zwar dann wenn die Artikel Nr. Spalte D der beiden Blätter übereinstimmen. Bei Übereinstimmung wird die SN: Nr. ohne Formatierung und der Status mit Formatierung kopiert. Gleichzeitig wird die betroffene Zeile aus Blatt "geplante Analysatoren (2)" gelöscht.
    Das Programm funktioniert einwandfrei. Da die originale Datei aber viel länger ist, dauert mir der Code zu lange. Daher hatte ich mit überlegt, das ganze im Array zu programmieren.
    Dazu habe ich 2 weiter Subs geschrieben (Status_2 & Status_3)

    Beim Sub 2 funktioniert die folgende Zeile noch also das kopieren ohne Formatierung

    Visual Basic-Quellcode

    1. i.Offset(0, 2) = Arr2(j, 6)


    Beim kopieren mit Formatierung und das löschen der Zeile meldet das Programm mir einen Fehler. Auch andere copy paste Methoden funktionierten nicht.

    Visual Basic-Quellcode

    1. Arr2(j, 9).Copy Destination:=i.Offset(0, 5)
    2. Tabelle2.Rows(Arr2(j)).Delete Shift:=xlUp


    Beim Sub 3 funktioniert auch das kopieren ohne Formatierung schon nicht mehr.

    Ich habe jetzt schon mehrere Tage verschieden Codes ausprobiert. Leider ohne Erfolg. Kann mir hier bitte jemand weiter helfen.
    Lg Wolfgang

    P.S. Das Blatt Archiv habe ich dran gehangen, damit man schneller wieder ausprobieren kann, weil das Programm ja die Zeilen löscht.
    Dateien
    • Test.xls

      (1,2 MB, 95 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Parawolli“ ()

    Hallo @Parawolli

    Der Arr2 kein Range, sondern ein Variant. d.H. da sind keine Formatierungen hinterlegt.
    Mach Option Explicit an, dann wirst du dazu gezwungen die Variablen richtig zu deklarieren.

    Hier einmal Sub Status_2() wie es aussehen könnte. (Ungetestet auf Richtigkeit des Ergebnisses)

    Visual Basic-Quellcode

    1. Sub Status_2()
    2. Dim Tabelle1 As Worksheet
    3. Dim Tabelle2 As Worksheet
    4. Dim i As Range
    5. Dim Arr2 As Range
    6. Dim EndeA As Integer
    7. Dim EndeB As Integer
    8. Dim j As Integer
    9. Set Tabelle1 = Worksheets("geplante Analysatoren")
    10. Set Tabelle2 = Worksheets("geplante Analysatoren (2)")
    11. EndeA = Tabelle1.Cells(Rows.Count, 4).End(xlUp).Row
    12. Tabelle2.Select
    13. EndeB = Tabelle2.Cells(Rows.Count, 4).End(xlUp).Row
    14. Set Arr2 = Tabelle2.Range(Tabelle2.Cells(3, 1), Tabelle2.Cells(EndeB, 10))
    15. Tabelle1.Select
    16. For Each i In Intersect(Tabelle1.UsedRange, Tabelle1.Range("D:D"))
    17. For j = LBound(Arr2.Value2, 1) To UBound(Arr2.Value2, 1)
    18. If i.Value = Arr2.Cells(j, 4).Value And i.Offset(0, 2) = "" And Arr2.Cells(j, 6).Value <> "" Then
    19. i.Offset(0, 2) = Arr2(j, 6) 'SN: Nr.
    20. Arr2(j, 9).Cells.Copy Destination:=i.Offset(0, 5) 'Status & Farbe
    21. Tabelle2.Rows(Arr2.Item(j).Row).Delete Shift:=xlUp 'Zeile löschen
    22. j = j - 1
    23. End If
    24. Next j
    25. Next i
    26. End Sub
    Hallo Henry
    erst einmal vielen Dank für Deine schnelle Hilfe. Ich bin leider erst jetzt dazu gekommen Deinen Code aus zu probieren.
    Er funktioniert auch bis auf eine Kleinigkeit.
    Er löscht mir an dieser Stelle immer 4 Zeilen über der eigentlichen (j) Zeile.

    Visual Basic-Quellcode

    1. Tabelle2.Rows(Arr2.Item(j).Row).Delete Shift:=xlUp

    Wenn man den Code mit F8 durchgeht, dann sieht man das die erste Übereinstimmung im Direktbereich bei j5 ist . Das ist Zeile 7 in Tabelle2
    Er löscht mir dann aber in Tabelle2 nicht Zeile 7 sondern Zeile 3.

    P.S. For j = LBound(Arr2.Value2, 1) To UBound(Arr2.Value2, 1)
    Die 2 hinter Value muss doch bestimmt weg, weil Tippfehler Oder?

    Dieser Beitrag wurde bereits 16 mal editiert, zuletzt von „Parawolli“ ()

    Hallo Henry,
    vielen Dank, genau das war das Problem!

    Ich hoffe ich darf Dir noch ein paar Verständnisfragen stellen.
    Wieso muss das Arr2 als Range und darf nicht als Variant deklariert werden?
    Bisher habe ich die Arrays immer mit einer Klammer als Variant deklariert. Also z.B. Dim Arr2()
    Dann hatte ich im Direktbereich immer so etwas stehen wie Arr2 : Variant(1 to 193, 1 to 10)
    Was mich wundert, das das Programm so wie ich es vorher geschrieben hatte ca. 5 sec. läuft und jetzt ca. 20 sec.
    Bitte nicht falsch verstehen,das soll absolut kein Vorwurf sein. Ich verstehe es nur nicht.

    Ich habe Dir zum besseren Verständnis noch einmal eine kl. Test Datei angehangen. Dort habe ich simple Rechenoperationen 1x ins Array programmiert und 1x normal.
    Das Array ist viel schneller, weil es zwar öfters rechnet aber nur 1x das Ergebnis im Array ausgibt. Das andere Programm gibt pro Rechnung einmal aus.
    Genau das hatte ich mir auch vorgestellt, aber irgendwie bekomme ich es nicht hin.
    Lg Wolfgang

    Dann
    Dateien
    • Test.xls

      (3,41 MB, 91 mal heruntergeladen, zuletzt: )
    Wie du dem Screenshot entnehmen kannst ist der Variant-Array eine Mischung aus Long/String/Double usw.
    Dass heisst die ganzen Informationen von Excel wie z.B. Zellenadresse, Zellenfarbe, Rahmen, Schriftart, Schriftgrösse usw. sind da nicht enthalten.

    Falls du nur mit den Zellwerten arbeitest, geht das in Ordnung, andernfalls benötigt es eben ein Range-Objekt.
    Bilder
    • ExcelVBAArray.JPG

      44,3 kB, 763×262, 86 mal angesehen
    OK habe ich verstanden.
    Mir ist aufgefallen, das ein Variant Array viel schneller ist, als ein Code ohne Array. (Siehe Code von gestern)
    Dagegen ist ein Range Array nicht schneller als ein Code ohne Array, das hatte ich ja bereits mit meinem Code und Deinem Code getestet.
    Bedeutet für mich, wenn ich nur den Zellenwert kopieren möchte, dann macht ein Variant Array im Code Sinn.
    Wenn ich dagegen mit Zelleninformationen arbeiten möchte, dann ist es egal ob ich ein Range Array mit in den Code programmiere oder nicht.
    Oder ich stehe auf dem Schlauch....
    Ich komme hier einfach nicht weiter...
    Der folgende Code funktioniert. Der Inhalt der Spalte A wird nach Spalte B kopiert. Und zwar alles auf einmal.
    Ich möchte aber, das auch die Zelleninformation (Sprich Zellenfarbe etc: mit kopiert wird.
    Daher wollte ich es als Range Array schreiben. Wenn ich also folgende Zeilen tausche 4 mit 5; 11 mit 12; 17 mit 18.
    Dann kopiert er mir in der Schleife jede Zeile einzeln und löscht nach der Schleife alles.
    Was mache ich falsch oder geht das gar nicht?

    Visual Basic-Quellcode

    1. Sub machs()
    2. Dim t As Double, i As Long, n
    3. Dim Arr()
    4. 'Dim Arr As Range
    5. Dim Tabelle1 As Worksheet
    6. Set Tabelle1 = Worksheets("Tabelle1")
    7. EndeA = Tabelle1.Cells(Rows.Count, 1).End(xlUp).Row
    8. Arr = Tabelle1.Range(Tabelle1.Cells(1, 1), Tabelle1.Cells(EndeA, 5))
    9. 'Set Arr = Tabelle1.Range(Tabelle1.Cells(1, 1), Tabelle1.Cells(EndeA, 5))
    10. For i = 1 To EndeA
    11. If Arr(i, 1) <> "" Then
    12. Arr(i, 2) = Arr(i, 1)
    13. 'Arr(i, 1).Copy Destination:=Arr(i, 2)
    14. End If
    15. Next i
    16. Tabelle1.Range(Tabelle1.Cells(1, 1), Tabelle1.Cells(EndeA, 5)) = Arr
    17. End Sub

    Dateien
    • Test.xls

      (2,88 MB, 82 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Parawolli“ ()

    Ersetze deinen kompletten Code durch einen Einzeiler.

    Visual Basic-Quellcode

    1. Sub MachsRichtig()
    2. Intersect(Tabelle1.UsedRange, Tabelle1.Range("A:A")).Copy Tabelle1.Range("B1")
    3. End Sub
    Das ist allemal perfomanter, als zeilenweises Vorgehen.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Hallo petaod,
    in diesem Fall hast Du natürlich Recht.
    In Wirklichkeit ist die If Bedingung aber eine andere, denn es werden über zwei Tabellen Werte miteinander verglichen und es darf natürlich nicht jeder Wert zurück gegeben werden.
    Ich hatte dieses Beispiel so einfach wie möglixch gewählt.
    Ich hätte in Zeile 16 auch schreiben können

    Visual Basic-Quellcode

    1. If Arr(i, 1) > 5 Then

    Das Programm soll die If Schleife durchlaufen, und die entsprechenden Zellen einmalig als Kopie ausgeben.
    Lg Wolfgang

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Parawolli“ ()

    Ich glaube ich bringe es falsch rüber was ich meine.
    Wenn ich den folgenden Code mit F8 durchgehe, dann geht das Programm zuerst die kompl. If Schleife durch, aber ohne jedesmal den Zelleinhalt bei beim Zutreffen der Bedingung von A nach B zu kopieren.
    Das macht er Einmalig erst in Zeile 23.
    Wenn ich dann wie gesagt die auskommentierten Zeilen also 4 durch 5; 11 durch 12; 17 durch 18 ersetze, dann kopiert er bereits in der If Schleife die Werte von A nach B, wenn die Bedingung zutrifft.

    Visual Basic-Quellcode

    1. Sub machs()
    2. Dim i As Long
    3. Dim Arr()
    4. 'Dim Arr As Range
    5. Dim Tabelle1 As Worksheet
    6. Set Tabelle1 = Worksheets("Tabelle1")
    7. EndeA = Tabelle1.Cells(Rows.Count, 1).End(xlUp).Row
    8. Arr = Tabelle1.Range(Tabelle1.Cells(1, 1), Tabelle1.Cells(EndeA, 5))
    9. 'Set Arr = Tabelle1.Range(Tabelle1.Cells(1, 1), Tabelle1.Cells(EndeA, 5))
    10. For i = 1 To EndeA
    11. If Arr(i, 1) > 5 Then
    12. Arr(i, 2) = Arr(i, 1)
    13. 'Arr(i, 1).Copy Destination:=Arr(i, 2)
    14. End If
    15. Next i
    16. Tabelle1.Range(Tabelle1.Cells(1, 1), Tabelle1.Cells(EndeA, 5)) = Arr
    17. End Sub

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „Parawolli“ ()

    Aber dann kann ich das Array auch kompl. weg lassen uns es standartmäßig so programmieren.
    Ist bei 1500 Zeilen genau so schnell wie die andere Variante. Ich erkenne dann keinen Vorteil mehr etwas im Array zu programmieren.

    Visual Basic-Quellcode

    1. Sub mach1()
    2. Dim i As Long
    3. Dim Tabelle1 As Worksheet
    4. Set Tabelle1 = Worksheets("Tabelle1")
    5. EndeA = Tabelle1.Cells(Rows.Count, 1).End(xlUp).Row
    6. For i = 1 To EndeA
    7. If Tabelle1.Cells(i, 1) > 5 Then
    8. Tabelle1.Cells(i, 1).Copy Destination:=Tabelle1.Cells(i, 2)
    9. End If
    10. Next i
    11. End Sub

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Parawolli“ ()

    Stimmt.
    Array bringt lediglich dann Performance-Vorteile wenn du nur einen Teil der Zellinformationen (z.B. Values) benötigst.
    Sobald du mehr Zellinformationen benötigst, ist Range das intelligentere Array.

    Sonst müsstest du für alle Teilinformationen (Values, Format, ...) eigene Arrays anlegen.
    Das lohnt sich nur bei ganz großen Datenmengen.

    Bei dieser Zuweisung

    Visual Basic-Quellcode

    1. Arr = Tabelle1.Range(Tabelle1.Cells(1, 1), Tabelle1.Cells(EndeA, 5))
    verwendest du implizit nur die Default-Property (und die ist Value).
    Was sich nämlich tatsächlich dahinter verbirgt:

    Visual Basic-Quellcode

    1. Arr = Tabelle1.Range(Tabelle1.Cells(1, 1), Tabelle1.Cells(EndeA, 5)).Value


    Übrigens:

    Parawolli schrieb:

    Dim Tabelle1 As Worksheet
    Set Tabelle1 = Worksheets("Tabelle1")
    Den Teil kannst du dir komplett sparen.
    Wie du in deinem VBA-Editor sehen kannst, hat dein Sheet bereits den Objektnamen Tabelle1.
    Da musst du nicht extra noch ein zusätzliches Objekt innerhalb der Prozedur dafür anlegen.
    Schon gar nicht mit demselben Namen. Das verwirrt nur.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Vielen Dank petaod
    jetzt habe ich es endlich verstanden.
    Ich muss mich ab jetzt mit der Deklarierung der Variablen und welche Informationen sich hinter den Formaten verstecken, viel mehr beschäftigen.

    Das ich nicht extra die Tabelle1 als Variable deklarieren muss ist etwas was selbst ich weiss. :thumbsup: Ich habe halt einfach nen Teil aus dem ganzen Programm kopiert und daduch ist es mit drin gewesen.
    Ich mache es aber sonst auch gerne wegen der Übersicht. Denn normalerweise heißen die Tabellenblätter nicht Tabelle1 ; 2; 3 .... wie im VB Explorer sondern "Analysatorreservierung" etc.
    Dann spare ich mir jedesmal z.B. zu schreiben Sheets("Analysatorreservierung").
    Es ist egal wie der Tabellennamen heisst.
    Wichtig ist der Objektname.
    Der bleibt, auch wenn du den Tabellennamen umbenennst.

    Aber auch dem kannst du einen vernünftigen Namen geben.
    Das ist dann besonders elegant.

    Beachte den Unterschied:
    Mit Sheets("abc").Range("A1") adressierst du über den Tabellennamen.
    Mit Tabelle1.Range("A1") adressierst du über den Objektnamen.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --