Valhalla Legends Forums Archive | Visual Basic Programming | Remove Array() by index

AuthorMessageTime
CrAz3D
I am aware that this has recently been posted, yet does not function to my needs.


I have my Array
[quote]http://
feany
gay
bob[/quote]

I can remove the first Array index(http://) correctly. However, if I try to remove the second index(feany) it removes the http:// aswell. But wait, there's more. When I remove the last index(bob) it just duplicates the first index(http://) aswell.

Remove Code
[code]For i = 0 To UBound(PhraseList) - 1
If LCase(pA(1)) = LCase(PhraseList(i)) Then
SendW "Removed phrase: " & PhraseList(i), strAccount
PhraseList(i) = vbNullString
ReDim Preserve PhraseList(UBound(PhraseList) - 1)
End If
Next i[/code]

Help is appreciatd! ::)
March 22, 2004, 7:47 PM
Stealth
Here's the most basic way to remove an item from an ARRAY. If you'll be doing it often you may want to look into a collection.

1. Create a new temporary array, dimensioned to (size - 1) of your start array.
2. Loop throguh your start array, copying everything but the index you want to remove. The temp array now contains your entire start array except the item you want to remove.
3. Redimension your start array to the size of the temp array.
4. Copy the temp array into the start array.
March 22, 2004, 8:04 PM
CrAz3D
[quote author=Stealth link=board=31;threadid=5914;start=0#msg50910 date=1079985897]
Here's the most basic way to remove an item from an ARRAY. If you'll be doing it often you may want to look into a collection.

1. Create a new temporary array, dimensioned to (size - 1) of your start array.
2. Loop throguh your start array, copying everything but the index you want to remove. The temp array now contains your entire start array except the item you want to remove.
3. Redimension your start array to the size of the temp array.
4. Copy the temp array into the start array.
[/quote]
I'll try a collection...thnx
March 22, 2004, 8:26 PM
Grok
[quote author=CrAz3D link=board=31;threadid=5914;start=0#msg50916 date=1079987170]
I'll try a collection...thnx
[/quote]

Bah. You learn not!
March 23, 2004, 2:20 AM
Lenny
Just a note, collections are much slower and less efficient than arrays, they should be avoided in general...

In addition, you could merely overwrite the array(index) you want to erase with array(index+1) and loop this, after this is finished you resize the array to (Ubound - 1) because the last array value will be a copy of the second to last....
March 23, 2004, 4:01 AM
Stealth
[quote author=Lenny link=board=31;threadid=5914;start=0#msg51067 date=1080014464]
Just a note, collections are much slower and less efficient than arrays, they should be avoided in general...

In addition, you could merely overwrite the array(index) you want to erase with array(index+1) and loop this, after this is finished you resize the array to (Ubound - 1) because the last array value will be a copy of the second to last....
[/quote]

That is indeed more efficient than I described. Does it work in all situations?
March 23, 2004, 4:25 AM
Flame
I did something similar to what Lenny said, but only for one purpose (coincidence, Phraseban!) and it seems to work fine. I can't explain it too well... but I'll just paste my code up here to see if you can get the idea. I haven't used it a lot, but with the little I have used it, it functions well.

[code]
Dim i As Integer
Dim RFP As Integer
If Phrasebans(0) = "" Then Exit Sub
For i = 0 To UBound(Phrasebans)
If LCase(Mid$(Message, 11)) = LCase(Phrasebans(i)) Then
Phrasebans(i) = ""
For RFP = i To UBound(Phrasebans)
If Phrasebans(RFP) = "" And RFP < UBound(Phrasebans) Then
Phrasebans(RFP) = Phrasebans(RFP + 1)
Phrasebans(RFP + 1) = ""
End If
Next RFP
If UBound(Phrasebans) = 0 Then
Phrasebans(0) = ""
Else
ReDim Preserve Phrasebans(0 To UBound(Phrasebans) - 1)
End If
Exit For
End If
Next i
[/code]
March 23, 2004, 4:40 AM
Stealth
That appears to be exactly what Lenny described.
March 23, 2004, 5:44 AM
Fr0z3N
uhh, I think Stealth has a good way, thats what I use.
March 23, 2004, 6:06 AM
o.OV
I read collections are slower if working
with about 100 items or less.
I don't use collections
so I can't give an opinion on that.

If the array does not need to be
in an order of any kind.
If a string.. switch the descriptor with last item
If a value.. item to remove equal to last item
last item not neccessarily the ubound,
and then zero out the last item
to kill off the extra item,
depending on how you want to handle it.
March 23, 2004, 6:50 AM
Adron
[quote author=Lenny link=board=31;threadid=5914;start=0#msg51067 date=1080014464]
Just a note, collections are much slower and less efficient than arrays, they should be avoided in general...
[/quote]

Where did you find this information? I was assuming that collections were some kind of binary tree which would make them very efficient for things like removing an item from the middle, looking up an item from a key, growing and shrinking.
March 23, 2004, 11:14 AM
Grok
http://www.mvps.org/vb/hardcore/html/collections201indexing.htm

and

http://www.mvps.org/vb/hardcore/html/walkingclistcollection.htm
March 23, 2004, 11:56 AM
CrAz3D
From what I see an Array is better in most opinions & according to facts. I will redo it to use an Array instead, thank you all.


There still seems to be a few problems that I cannot fiugre out.
[quote][8:05:42 AM] «CrAz3D[xL]» \flist
[8:05:42 AM] «0x69» Current Filters are: http, stealth, bob, gay, feany, telrin
[8:05:46 AM] «CrAz3D[xL]» \frem http
[8:05:46 AM] «0x69» Removed filter: http
[8:05:48 AM] «CrAz3D[xL]» \flist
[8:05:48 AM] «0x69» Current Filters are: stealth, bob, gay, feany, telrin
[8:05:53 AM] «CrAz3D[xL]» \frem telrin
[8:05:53 AM] «0x69» Removed filter: telrin
[8:05:55 AM] «CrAz3D[xL]» \flist
[8:05:55 AM] «0x69» Current Filters are: bob, gay, feany, feany[/quote]
[code]For i = 0 To UBound(FilterList) - 1
If LCase(pA(1)) = LCase(FilterList(i)) Then
SendW "Removed filter: " & FilterList(i), strAccount
FilterList(i) = FilterList(i + 1)
ReDim Preserve FilterList(UBound(FilterList) - 1)
End If
Next i[/code]
I have a feeling the it is the "ReDim Preserve" portion that I am screwing up.
March 23, 2004, 2:58 PM
drivehappy
Your ReDim statement appears correct.

[code]
FilterList(i) = FilterList(i + 1)
[/code]
This however only moves the next element into the current's position - not all subsequent elements in the array. If 'i' is at the end of the array an out of bounds error may occur if you try accessing the next element that is not there. I cannot see how your first element is removed though.
March 23, 2004, 4:45 PM
CrAz3D
hmm, ok...I'll mess w/the Filterlist - w/e
March 23, 2004, 4:50 PM
Eli_1
assumes:
Filters() = your filter list
removing = string you want to remove

[code]
dim tmp() as string

redim tmp(0)

for i = 0 to ubound(filters)
if lcase(filters(i)) <> lcase(removing) and filters(i) <> "" then
tmp(ubound(tmp)) = filters(i)
redim preserve tmp(ubound(tmp) + 1)
end if
next i

redim preserve tmp(ubound(tmp) - 1)
redim filters(ubound(filters) - 1)

filters = tmp
[/code]

This is just something I typed up real fast, so there's bound to be an error somewhere, or it might not work at all ;)

[edit 1] fixed code tags
[edit 2] fixed code typos
March 23, 2004, 7:38 PM
CrAz3D
That's basically what I ended up doing, it wokrs fine now. Thanks
March 23, 2004, 7:45 PM
Eli_1
oh ok, I tryed ;D
March 23, 2004, 7:50 PM
Adron
I did a small test of the laziest possible coding. In this test, a collection is more than 20 times faster than an array.

Command1: 0.5 seconds data generation
Command2: 49 seconds for an array
Command3: 2.2 seconds for a collection

[code]
Option Explicit

Dim testdata(100000) As String
Dim removedata(1000) As String

Private Sub swap(a As String, b As String)
Dim tmp As String
tmp = a
a = b
b = tmp
End Sub

Private Sub Command1_Click()
Dim t
t = Timer
Dim i As Long
For i = 0 To 100000
testdata(i) = i
Next i
For i = 0 To 100000
swap testdata(i), testdata(Rnd * 100000)
Next i
For i = 0 To 1000
removedata(i) = testdata(Fix(Rnd * 100) * 1000 + i)
Next i
MsgBox Timer - t
End Sub

Private Sub Command2_Click()
Dim t
t = Timer
Dim ar() As String
Dim i As Long, j As Long, k As Long
For i = 0 To 100000
ReDim Preserve ar(i) As String
ar(i) = testdata(i)
Next i
For i = 0 To 1000
For j = 0 To UBound(ar)
If ar(j) = removedata(i) Then
For k = j To UBound(ar) - 1
ar(k) = ar(k + 1)
Next k
Exit For
End If
Next j
Next i
MsgBox Timer - t
End Sub

Private Sub Command3_Click()
Dim t
t = Timer
Dim i As Long
Dim co As New Collection
For i = 0 To 100000
co.Add testdata(i), testdata(i)
Next i
For i = 0 To 1000
co.Remove removedata(i)
Next i
MsgBox Timer - t
End Sub
[/code]
March 23, 2004, 10:33 PM
CrAz3D
Well, now that I am utterly confused on which to use I'll just ask for more opinions. Any?
March 24, 2004, 1:16 AM
Grok
[quote author=CrAz3D link=board=31;threadid=5914;start=15#msg51270 date=1080090984]
Well, now that I am utterly confused on which to use I'll just ask for more opinions. Any?
[/quote]

You have just read the results of an actual test, and you ask for opinions? Either verify the test yourself or find refuting evidence. Other opinions are useless in the face of evidence.
March 24, 2004, 4:10 AM
CrAz3D
[quote author=Grok link=board=31;threadid=5914;start=15#msg51331 date=1080101417]
[quote author=CrAz3D link=board=31;threadid=5914;start=15#msg51270 date=1080090984]
Well, now that I am utterly confused on which to use I'll just ask for more opinions. Any?
[/quote]

You have just read the results of an actual test, and you ask for opinions? Either verify the test yourself or find refuting evidence. Other opinions are useless in the face of evidence.
[/quote]
From what I read in about posted links it said that arrays were more effective.
March 24, 2004, 4:22 AM
Adron
[quote author=CrAz3D link=board=31;threadid=5914;start=15#msg51334 date=1080102126]
From what I read in about posted links it said that arrays were more effective.
[/quote]

The answer is that neither is more effective always, it depends on what you want to do. If you need to find an item and then remove it from the middle (which seemed to be what this question was about) then using a collection may be more effective. Of course, simple optimizations such as reordering the array instead of moving all items up, not rediming it all the time etc may make an array faster.

I chose to use code like that which has been posted here in this thread for the array, and the simplest possible code for the collection.
March 24, 2004, 3:09 PM
drivehappy
What is a collection, I've always used arrays within VB. Are they much like linked lists?
March 24, 2004, 5:30 PM
Adron
[quote author=drivehappy link=board=31;threadid=5914;start=15#msg51428 date=1080149423]
What is a collection, I've always used arrays within VB. Are they much like linked lists?
[/quote]

I don't know how they are really implemented. They look to me like a c++ map<string, void*>. They are probably good at things that linked lists are good at, but also at looking up items from a string. They have a higher overhead than arrays. I think that a VB array is treated as a native data structure that the compiler can optimize while accessing a collection always means making a function call.
March 24, 2004, 5:56 PM
o.OV
Started new project
copy and pasted code
placed 4 command buttons on form
compiled into executable
ran executable
clicked in order..

command_1 1.097656
command_2 108.5273
command_3 42.46094
command_4 16.5

My results came out differently..
Is there something else I have to add to the project?

command_4 is just my version of command_2

[code]

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)

Private Sub Command4_Click()

Dim t As Long
Dim i As Long
Dim j As Long
Dim P As Long
Dim C As Long

Dim TEMPdata() As String

t = Timer

For i = 0 To 100000
ReDim Preserve TEMPdata(i) As String
TEMPdata(i) = testdata(i)
Next i

For i = 0 To 1000
P = UBound(TEMPdata)
For j = 0 To P
If removedata(i) = TEMPdata(j) Then
C = StrPtr(TEMPdata(P))
CopyMemory ByVal VarPtr(TEMPdata(P)), ByVal VarPtr(TEMPdata(j)), 4
CopyMemory ByVal VarPtr(TEMPdata(j)), C, 4
ReDim Preserve TEMPdata(P - 1) As String
Exit For
End If
Next j
Next i

MsgBox Timer - t

End Sub

[/code]

Add-On:
I was expecting command_3 to take less then 10 seconds. Any ideas?
March 24, 2004, 7:23 PM
Adron
[quote author=o.OV link=board=31;threadid=5914;start=15#msg51461 date=1080156227]
Started new project
copy and pasted code
placed 4 command buttons on form
compiled into executable
ran executable
clicked in order..

command_1 1.097656
command_2 108.5273
command_3 42.46094
command_4 16.5

My results came out differently..
Is there something else I have to add to the project?
[/quote]

No, I just verified it, trying it in both vb5 and vb6 and with p-code and native code. Native code cuts my array time down to ~30 seconds, and collection code to around 1.8 seconds. Command3 never reaches 3 seconds.

The collection seems to use about twice as much memory. Perhaps you're low on memory?
March 24, 2004, 7:38 PM
o.OV
Yea.. maybe low memory.
196 megabytes of memory is considered
inadequate by most. heh ;D
and my processor is a 500mhz amd

Add-On:
And I did reboot before running.
I had at least 75 megabytes
of physical memory available at run time.

If memory really is a problem..
I am better off with a simple array.
But I want to test this collection thing anyways.
I'm gonna go and cut the array sizes down
and see if that helps.
March 24, 2004, 7:50 PM
o.OV
Adron, I need you to confirm that my changes were made correctly.

list of changes:
Timer is now GetTickCount
100000 is now 1000
command_1 has been modified

[code]

Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
Private Declare Function GetTickCount Lib "kernel32" () As Long

Dim testdata(1000) As String
Dim removedata(1000) As String

Private Sub swap(a As String, b As String)
Dim tmp As String
tmp = a
a = b
b = tmp
End Sub

Private Sub Command1_Click()
Dim t
t = GetTickCount
Dim i As Long
For i = 0 To 1000
testdata(i) = i
removedata(i) = i
Next i
For i = 0 To 1000
swap testdata(i), testdata(Rnd * 1000)
swap removedata(i), removedata(Rnd * 1000)
Next i
MsgBox GetTickCount - t
End Sub

Private Sub Command2_Click()
Dim t
t = GetTickCount
Dim ar() As String
Dim i As Long, j As Long, k As Long
For i = 0 To 1000
ReDim Preserve ar(i) As String
ar(i) = testdata(i)
Next i
For i = 0 To 1000
For j = 0 To UBound(ar)
If ar(j) = removedata(i) Then
For k = j To UBound(ar) - 1
ar(k) = ar(k + 1)
Next k
Exit For
End If
Next j
Next i
MsgBox GetTickCount - t
End Sub

Private Sub Command3_Click()
Dim t
t = GetTickCount
Dim i As Long
Dim co As New Collection
For i = 0 To 1000
co.Add testdata(i), testdata(i)
Next i
For i = 0 To 1000
co.Remove removedata(i)
Next i
MsgBox GetTickCount - t
End Sub

Private Sub Command4_Click()

Dim t As Long
Dim i As Long
Dim j As Long
Dim P As Long
Dim C As Long

Dim TEMPdata() As String

t = GetTickCount

For i = 0 To 1000
ReDim Preserve TEMPdata(i + 1) As String
TEMPdata(i) = testdata(i)
Next i
For i = 0 To 1000
P = UBound(TEMPdata)
For j = 0 To P
If removedata(i) = TEMPdata(j) Then
C = StrPtr(TEMPdata(P))
CopyMemory ByVal VarPtr(TEMPdata(P)), ByVal VarPtr(TEMPdata(j)), 4
CopyMemory ByVal VarPtr(TEMPdata(j)), C, 4
ReDim Preserve TEMPdata(P - 1) As String
Exit For
End If
Next j
Next i

MsgBox GetTickCount - t

End Sub

[/code]
March 25, 2004, 8:13 AM
CrAz3D
[code]Private Sub Command1_Click()
Dim t
t = Timer
Dim i As Long
For i = 0 To 100000
testdata(i) = i
Next i
For i = 0 To 100000
swap testdata(i), testdata(Rnd * 100000)
Next i
For i = 0 To 1000
removedata(i) = testdata(Fix(Rnd * 100) * 1000 + i)
Next i
MsgBox Timer - t
End Sub[/code]

I understand what Command2 & 3 are, but what is Command1 exactly? I read that it is a data generation, but what does a data generation do?
March 25, 2004, 4:11 PM
Stealth
Creates a set of sample data for use in testing the speed of the array/collection.
March 25, 2004, 8:04 PM
CrAz3D
Oh, heh. Silly me. Thanks
March 25, 2004, 8:43 PM
Adron
[quote author=o.OV link=board=31;threadid=5914;start=15#msg51598 date=1080202431]
Adron, I need you to confirm that my changes were made correctly.

list of changes:
Timer is now GetTickCount
100000 is now 1000
command_1 has been modified
[/quote]

Changing it from 100000 to 1000 is a huge change. I don't think you'll get very testable results from that because times should decrease too much, as in a collection going from 2 seconds to 0.02, which is close to how small times VB can measure.
March 25, 2004, 11:31 PM
o.OV
[quote author=Adron link=board=31;threadid=5914;start=30#msg51672 date=1080257481]
[quote author=o.OV link=board=31;threadid=5914;start=15#msg51598 date=1080202431]
Adron, I need you to confirm that my changes were made correctly.

list of changes:
Timer is now GetTickCount
100000 is now 1000
command_1 has been modified
[/quote]

Changing it from 100000 to 1000 is a huge change. I don't think you'll get very testable results from that because times should decrease too much, as in a collection going from 2 seconds to 0.02, which is close to how small times VB can measure.
[/quote]

I only decreased it like this because memory
may have been a problem.
About the timing..
milliseconds seem to work well enough.
The results are consistent in the order of ranking.

command_1 25ms
command_2 1406ms
command_3 374ms
command_4 122

I'm still puzzled as to why command_3
still isn't performing to expectations for me.
the memory usage for the collection should be
about 100 times smaller..
so it can't still be a problem with memory..
can it?
March 26, 2004, 9:20 AM
Adron
Yes, that's strange... I'd love to see some results from other people - try the code and post whether my or o.OV's results are odd.
March 26, 2004, 4:43 PM
CrAz3D
[quote]Native Fast:
   com1:.171
   com2:12.283
   com3:.968
   com4:5.015

Native Small:
   com1:.171
   com2:12.656
   com3:1.015
   com4:5.171

Native No:
   com1:.171
   com2:12.437
   com3:.984
   com4:5.796

PCode:
   com1:.203
   com2:20.640
   com3:1.031
   com4:9.687[/quote]

All seem to work for me

(com4 is o.Ov's)
March 26, 2004, 7:24 PM
Adron
Hmmk, so, the odd results are o.OV's. Now I wonder why he's getting so bad results for collections...
March 26, 2004, 8:15 PM
o.OV
*gives computer a mean kick* >:(

I'm gonna go check MSDN for anything relevant to my odd results.
March 27, 2004, 4:06 AM
drivehappy
http://www.experts-exchange.com/Programming/Programming_Languages/Visual_Basic/Q_20873546.html

Doesn't really account for the time differences between Adron's results and O.o's but it could possibly be the removal of the collections elements causing some delay on lower memory systems.
March 27, 2004, 8:31 AM

Search