Array elemente verschieben, bis zu letzem Eintrag

Hallo,

ich stehe gerade etwas auf dem Schlauch…

Ich habe ein Array, hier werden Texte Eingefügt.

Beispiel

Element (1) Test1
Element (2) Test2
Element (3) Test3
Element (4) „“
Element (5) Test4
Element (6) Test5
Element (7) „“
Element (8) Test6

Nun hätte ich gerne, dass die Elemente so verschoben werden, dass keine Leeren Einträge mehr vorhanden sind.

Danke schonmal.
Hoffe es ist genaugenug beschrieben.

Hallo Paul,

versuch’s mal damit:

Option Base 1
Sub zusammenschieben()
 Dim element(8)
 Dim i As Integer, j As Integer

 element(1) = "Test1"
 element(2) = "Test2"
 element(3) = "Test3"
 element(4) = ""
 element(5) = "Test4"
 element(6) = "Test5"
 element(7) = ""
 element(8) = "Test6"

 For i = 1 To UBound(element)
 If element(i) = "" Then
 For j = i To UBound(element) - 1
 element(j) = element(j + 1)
 Next j
 element(UBound(element)) = ""
 End If
 Next i
End Sub

Gruß, Andreas

Nun hätte ich gerne, dass die Elemente so verschoben werden,
dass keine Leeren Einträge mehr vorhanden sind.

Danke schonmal.
Hoffe es ist genaugenug beschrieben.

Hallo Paul,

Option Explicit
Option Base 1

Sub zusammenschieben()
Dim element(), i As Integer, j As Integer, zaehl As Integer
ReDim element(8)
element(1) = "d"
element(2) = "Test2"
element(3) = "Test3"
element(4) = ""
element(5) = "Test4"
element(6) = "Test5"
element(7) = "w"
element(8) = ""
For i = 1 To UBound(element)
 If element(i) = "" Then
 zaehl = zaehl + 1
 For j = i To UBound(element) - 1
 element(j) = element(j + 1)
 Next j
 End If
Next i
If zaehl Then ReDim Preserve element(UBound(element) - zaehl)
End Sub

Gruß
Reinhard

Hervorragend!

Ist des was ich wollte!

Dankeschön…

OT: Abgekupfert? :wink:
Hallo Reinhard,

ich frag’ jetzt nur mal spaßhalber: Hast du mein Posting gelesen, bevor du deine SUB hier reingestellt hast? (Sogar der Name der SUB ist identisch!)

Gruß und nix für ungut
Andreas

Hallo Reinhard,

ich frag’ jetzt nur mal spaßhalber: Hast du mein Posting
gelesen, bevor du deine SUB hier reingestellt hast? (Sogar der
Name der SUB ist identisch!)

Da bei den TextStrings etwas unterschied vorhanden ist, ist es schwer Geguttenbergt und nicht nur einfach Abgekupfert :smile:

Hallo!

(Sogar der Name der SUB ist identisch!)

Dafür leistet aber die Sub auch tatsächlich das, was der Name suggeriert und der OP auch wollte.

Jan

Was läuft denn hier auf einmal?

ich frag’ jetzt nur mal spaßhalber: Hast du mein Posting
gelesen, bevor du deine SUB hier reingestellt hast? (Sogar der
Name der SUB ist identisch!)

Hallo Andreas,

ja, ich habe dein Posting gelesen, daraus deine Sub rauskopiert,
dann für mich wesentliche Dinge verändert und wieder als meinen Beitrag hier eingestellt.

Deine Sub ist die Basis für meine Sub aber sie sind nicht identisch.
Und zu abgekupferet oder Guttenbergisch, naja wenn sowas kommt antworte ich zurück, wer sich in Vba auskennt der sieht den gewaltigen Unterschied zwischen deinem Code und meinen.
Wer nicht sollte sich dann da doch raushalten.

Es ist in Foren Usus den Code eines Anfragers oder eines anderen Antworters zu nehmen und den zu vewrbessern.
Schwachfug mit kupfern oder Guttenberg.

Meinst du im Ernst ich hätte den Gesamtcode nicht binnen weniger Minuten selbst geschrieben ohne deinen je gesehen zu haben?
Dann kurz getestet und fertig.

Gruß
Reinard

[MOD] abgeschlossen wegen OT (owt)

Hallo,

schön, dass du mit den angegebenen Lösungen zufrieden bist, ich wäre es nicht. Für nennenswerte Array-Größen sind nämlich beide grausig ineffizient , weil für jede Lücke alle folgenden Elemente kopiert werden, inklusive der überflüssig gewordenen Kopien am Feldende. Also verhält sich die Laufzeit im schlechtesten Fall (alle Elemente sind leer) quadratisch zur Anzahl der Feldelemente (das ist nicht einmal für brauchbare Sortierverfahren nötig) anstatt linear. Ich würde mit einem Lese- und einem Schreibindex arbeiten, die beide durch das Array wandern. Der Schreibindex wird immer um 1 erhöht, der Leseindex läuft schneller, weil er leere Elemente überspringen darf. Sobald der Leseindex das Ende des Felds erreicht, war’s das. Die Implementierung überlasse ich VB-Nutzern als Übung…

Grüße, guidot

Hallo Guidot,

schön, dass du mit den angegebenen Lösungen zufrieden bist,
ich wäre es nicht. Für nennenswerte Array-Größen sind nämlich
beide grausig ineffizient , weil für jede Lücke alle folgenden
Elemente kopiert werden, inklusive der überflüssig gewordenen
Kopien am Feldende.

ich sehe das so, wenn der Anfrager das makro mit einem Button startet und das Ergebnis ist einen Tick, eine Sekunde später da so ist das in Ordnung.
Dauert es länger kann er das sagen, dann wird versucht den Code zeitlich zu optimieren.
Dem war nicht der Fall.

Erinnert mich an die Sache mit dem Code um rauszufinden ob eine Zahl eine Primzahl ist oder nicht mittels einer VBa-Funktion.
Dieser im Rahmen eines Gesamtprojektes wo es noch um andere Funktionen wie Quersumme u.ä. ging.
Quersumme, eine dritte Funktion und den Gesamtcode habe ich selbst gebastelt, für Primzahl einen Code aus dem Internet gefischt, getestet und eingebaut.

Warum sollte ich mir da Gedanken machen etwas von 700 ms Dauer auf 350 ms dauer zu optimieren?
Nachstehend ist Code von Franz zum Primzahltest, meinste der wäre nötig gewesen in meinem Fall wo auch die „ineffiziente“ Primzahlfunktion dicke schnell genug ist?
Dito hier das mit den Arrays.

Array wandern. Der Schreibindex wird immer um 1 erhöht, der
Leseindex läuft schneller, weil er leere Elemente überspringen
darf.

Das würde mich interessieren, wieso wodurch, wie , überspringt da der LeseIndex Elemente, wie kriegt er raus daß sie leer sind?

Sobald der Leseindex das Ende des Felds erreicht, war’s
das. Die Implementierung überlasse ich VB-Nutzern als Übung…

Es geht um VBA, da gibt es manches nicht von VB wie diesen einen Pointer, weiß den Namen grad nicht.

Gruß
Reinhard

Function IsPrim(lngZahl As Long) As Boolean
 Dim l As Long
 Dim lMax As Long
 Select Case lngZahl
 Case 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 33, 37, 41, 43, 47, \_
 53, 59, 61, 67, 71, 73, 79, 83, 89, 97
 IsPrim = True
 Exit Function
 Case Else
 If lngZahl Mod 2 = 0 Then Exit Function
 If lngZahl Mod 3 = 0 Then Exit Function
 If lngZahl Mod 5 = 0 Then Exit Function
 If lngZahl Mod 7 = 0 Then Exit Function
 If lngZahl Mod 11 = 0 Then Exit Function
 If lngZahl Mod 13 = 0 Then Exit Function
 If lngZahl Mod 17 = 0 Then Exit Function
 If lngZahl Mod 19 = 0 Then Exit Function
 If lngZahl Mod 23 = 0 Then Exit Function
 If lngZahl Mod 29 = 0 Then Exit Function
 If lngZahl Mod 33 = 0 Then Exit Function
 If lngZahl Mod 37 = 0 Then Exit Function
 If lngZahl Mod 41 = 0 Then Exit Function
 If lngZahl Mod 43 = 0 Then Exit Function
 If lngZahl Mod 47 = 0 Then Exit Function
 If lngZahl Mod 53 = 0 Then Exit Function
 If lngZahl Mod 59 = 0 Then Exit Function
 If lngZahl Mod 61 = 0 Then Exit Function
 If lngZahl Mod 67 = 0 Then Exit Function
 If lngZahl Mod 71 = 0 Then Exit Function
 If lngZahl Mod 73 = 0 Then Exit Function
 If lngZahl Mod 79 = 0 Then Exit Function
 If lngZahl Mod 83 = 0 Then Exit Function
 If lngZahl Mod 89 = 0 Then Exit Function
 If lngZahl Mod 97 = 0 Then Exit Function
 End Select
 lMax = CLng(lngZahl ^ 0.5)
 For l = 101 To lMax Step 10
 If lngZahl Mod l = 0 Then Exit Function
 Next
 For l = 103 To lMax Step 10
 If lngZahl Mod l = 0 Then Exit Function
 Next
 For l = 107 To lMax Step 10
 If lngZahl Mod l = 0 Then Exit Function
 Next
 For l = 109 To lMax Step 10
 If lngZahl Mod l = 0 Then Exit Function
 Next
 IsPrim = (l \> lMax - 1)
End Function

Hallo!

Array wandern. Der Schreibindex wird immer um 1 erhöht, der
Leseindex läuft schneller, weil er leere Elemente überspringen
darf.

Das würde mich interessieren, wieso wodurch, wie , überspringt
da der LeseIndex Elemente, wie kriegt er raus daß sie leer
sind?

So in etwa ginge das wohl (Pseudocode):

iwrite = 1 
For iread = 1 To UBound(element)
 If element(iread) "" Then
 If iread \> iwrite Then
 element(iwrite) = element(iread)
 element(iread) = ""
 End If
 iwrite = iwrite + 1
 End If
Next iread

Und iwrite kann dann anschließend auch für das Redimensionieren genutzt werden.

Gruß
Jan

Hallo Jan,

Array wandern. Der Schreibindex wird immer um 1 erhöht, der
Leseindex läuft schneller, weil er leere Elemente überspringen
darf.

Das würde mich interessieren, wieso wodurch, wie , überspringt
da der LeseIndex Elemente, wie kriegt er raus daß sie leer
sind?

So in etwa ginge das wohl (Pseudocode):

For iread = 1 To UBound(element)

das meine ich doch, iread oder dieser Leseindex geht doch alles einzeln durch ob es „leer“ ist, da ist nix mit überspringen soweit ich weiß.

Und iwrite kann dann anschließend auch für das
Redimensionieren genutzt werden.

ReDim ist gut und schön, macht aber den Code langsam wenn es schon um inneffizient geht.
Schneller ist das array großzügig zu dimensionieren, dann die Anzahl der Einträge die dazu kommen mitzuzählen.

Und jetzt kommt dieser Befehl oder wie auch immer man es bezeichnet was VB hat und Vba nicht zum Tragen,
damit kann man aus arrA(10000) daß aber nur 4711 Einträge hat, aufgrund der Mitzählung die man gemacht hat, nur diese in arrB(4711) kopieren.

Gruß
Reinhard

Gruß
Jan

Moin!

das meine ich doch, iread oder dieser Leseindex geht doch alles einzeln :durch ob es „leer“ ist, da ist nix mit überspringen soweit ich weiß.

Das Überspringen geschieht im Bezug auf das Umkopieren. Um die Abfrage, ob eine Zeichenkette leer ist, kommt man nicht rum.
Beispiel: „A“,"","",„B“,"","","C"
Bei Andreas’ Lösung werden, wenn ich das richtig überschlage, 12-mal ein String umkopiert, ungeachtet ob leer oder nicht. Bei der Index-Lösung gibt es nur 2-mal ein Umkopieren; die Leerstrings werden übergangen.

ReDim ist gut und schön, macht aber den Code langsam wenn es schon um inneffizient geht.
Schneller ist das array großzügig zu dimensionieren, dann die Anzahl der Einträge die dazu kommen mitzuzählen.

Missverständnis. „Und iwrite kann dann anschließend auch für das
Redimensionieren genutzt werden.“
Also genauso wie bei deiner Lösung.

Gruß
Jan

ich sehe das so, wenn der Anfrager das makro mit einem Button
startet und das Ergebnis ist einen Tick, eine Sekunde später
da so ist das in Ordnung.
Dauert es länger kann er das sagen, dann wird versucht den
Code zeitlich zu optimieren.
Dem war nicht der Fall.

Die weit verbreitete Meinung, Skriptsprachen seien minderwertig und darin geschriebene Programme anders zu betrachten, als solche in „richtigen“ Sprachen, teile ich nicht. Aus dem Beispiel mit 8 Elementen würde ich auch nicht schließen, dass der Frager nur geringe Datenmengen damit verarzten möchte. Ich mache schon Zugeständnisse: ein einfacheres Programm darf etwas langsamer sein.

Aber in Python (Felder beginnen mit Index Null, leere Zeichenketten werden als FALSE aufgefasst) sähe die Routine so aus (Danke an Jan für die Anregung, den Schreibindex als Schleifenvariable herzunehmen):

def compact(anArray):
 writeIndex = 0

 # optional optimization: avoid copying value to same place before
 # first gap; throws exception, if array is completely empty
 while anArray[writeIndex]:
 writeIndex += 1

 # start real work 
 for readIndex in range(writeIndex, len(anArray)):
 readValue = anArray[readIndex]
 if readValue:
 anArray[writeIndex] = readValue
 writeIndex += 1

 # truncate array to remaining data
 del(anArray[writeIndex:]):

Das ist einfacher und schneller, unabhängig von der Sprache.

Warum sollte ich mir da Gedanken machen etwas von 700 ms Dauer
auf 350 ms dauer zu optimieren?

Über einen Faktor zwei würde ich kein Wort verlieren, aber quadratisches Wachstum heißt, dass der Faktor 100 schnell erreicht ist und es noch viel schlimmer wird.

Nachstehend ist Code von Franz zum Primzahltest, meinste der
wäre nötig gewesen in meinem Fall wo auch die „ineffiziente“
Primzahlfunktion dicke schnell genug ist?

Ich weiß nicht, wie große Zahlen du hineinstecken möchtest, mag persönlich aber den angegebenen Code nicht. Die kleinen Primzahlen kommen doppelt vor (im case und in den einzelnen Tests), die vierfache Laufschleife ist mäßig elegant (weil sie vierfachen Overhead bedeutet). Der Code ist nicht einfach in Richtung komplette Primfaktorzerlegung aufzurüsten, weil die Testfaktoren nicht mehr monoton steigen.
Wenn man die Vielfachen von zwei, drei und fünf ausblenden will (das ist schon besser als der angegebene Code, der ab hundert nur die Vielfachen von 2 und 5 ausblendet), braucht man den Probeteiler der Reihe nach (ab sieben gerechnet) um [4, 2, 4, 2, 4, 6, 2, 6] Periode inkrementieren, weil das netterweise acht Elemente sind, ist nur ein bitweises UND für den Index in dieses Array nötig. Vielfache von 7 sind dann unter den den ersten hundert so wenige übrig (49 und 77), dass ich das Array mit den Zahlen bis 97 für verzichtbar halte.

Ansonsten sollte man bei richtig großen Eingabe-Zahlen und wenn es nur auf Primzahl ja/nein ankommt, nach dem Prüfen auf kleine Faktoren als nächstes einen Fermat-Test machen (sagt D. E. Knuth).

Grüße und nichts für ungut :smile:,
guidot