Valhalla Legends Archive

Programming => General Programming => Visual Basic Programming => Topic started by: CrAz3D on March 22, 2004, 01:47 PM

Title: Remove Array() by index
Post by: CrAz3D on March 22, 2004, 01:47 PM
I am aware that this has recently been posted, yet does not function to my needs.


I have my Array
Quotehttp://
feany
gay
bob

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
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


Help is appreciatd!  ::)
Title: Re:Remove Array() by index
Post by: Stealth on March 22, 2004, 02:04 PM
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.
Title: Re:Remove Array() by index
Post by: CrAz3D on March 22, 2004, 02:26 PM
Quote from: Stealth on March 22, 2004, 02:04 PM
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.
I'll try a collection...thnx
Title: Re:Remove Array() by index
Post by: Grok on March 22, 2004, 08:20 PM
Quote from: CrAz3D on March 22, 2004, 02:26 PM
I'll try a collection...thnx

Bah.  You learn not!
Title: Re:Remove Array() by index
Post by: Lenny on March 22, 2004, 10:01 PM
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....
Title: Re:Remove Array() by index
Post by: Stealth on March 22, 2004, 10:25 PM
Quote from: Lenny on March 22, 2004, 10:01 PM
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....

That is indeed more efficient than I described. Does it work in all situations?
Title: Re:Remove Array() by index
Post by: Flame on March 22, 2004, 10:40 PM
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.


           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
Title: Re:Remove Array() by index
Post by: Stealth on March 22, 2004, 11:44 PM
That appears to be exactly what Lenny described.
Title: Re:Remove Array() by index
Post by: Fr0z3N on March 23, 2004, 12:06 AM
uhh, I think Stealth has a good way, thats what I use.
Title: Re:Remove Array() by index
Post by: o.OV on March 23, 2004, 12:50 AM
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.
Title: Re:Remove Array() by index
Post by: Adron on March 23, 2004, 05:14 AM
Quote from: Lenny on March 22, 2004, 10:01 PM
Just a note, collections are much slower and less efficient than arrays, they should be avoided in general...

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.
Title: Re:Remove Array() by index
Post by: Grok on March 23, 2004, 05:56 AM
http://www.mvps.org/vb/hardcore/html/collections201indexing.htm (http://www.mvps.org/vb/hardcore/html/collections201indexing.htm)

and

http://www.mvps.org/vb/hardcore/html/walkingclistcollection.htm (http://www.mvps.org/vb/hardcore/html/walkingclistcollection.htm)
Title: Re:Remove Array() by index
Post by: CrAz3D on March 23, 2004, 08:58 AM
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
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

I have a feeling the it is the "ReDim Preserve" portion that I am screwing up.
Title: Re:Remove Array() by index
Post by: drivehappy on March 23, 2004, 10:45 AM
Your ReDim statement appears correct.


FilterList(i) = FilterList(i + 1)

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.
Title: Re:Remove Array() by index
Post by: CrAz3D on March 23, 2004, 10:50 AM
hmm, ok...I'll mess w/the Filterlist - w/e
Title: Re:Remove Array() by index
Post by: Eli_1 on March 23, 2004, 01:38 PM
assumes:
Filters() = your filter list
removing = string you want to remove


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


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
Title: Re:Remove Array() by index
Post by: CrAz3D on March 23, 2004, 01:45 PM
That's basically what I ended up doing, it wokrs fine now.  Thanks
Title: Re:Remove Array() by index
Post by: Eli_1 on March 23, 2004, 01:50 PM
oh ok, I tryed  ;D
Title: Re:Remove Array() by index
Post by: Adron on March 23, 2004, 04:33 PM
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


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
Title: Re:Remove Array() by index
Post by: CrAz3D on March 23, 2004, 07:16 PM
Well, now that I am utterly confused on which to use I'll just ask for more opinions.  Any?
Title: Re:Remove Array() by index
Post by: Grok on March 23, 2004, 10:10 PM
Quote from: CrAz3D on March 23, 2004, 07:16 PM
Well, now that I am utterly confused on which to use I'll just ask for more opinions.  Any?

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.
Title: Re:Remove Array() by index
Post by: CrAz3D on March 23, 2004, 10:22 PM
Quote from: Grok on March 23, 2004, 10:10 PM
Quote from: CrAz3D on March 23, 2004, 07:16 PM
Well, now that I am utterly confused on which to use I'll just ask for more opinions.  Any?

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.
From what I read in about posted links it said that arrays were more effective.
Title: Re:Remove Array() by index
Post by: Adron on March 24, 2004, 09:09 AM
Quote from: CrAz3D on March 23, 2004, 10:22 PM
From what I read in about posted links it said that arrays were more effective.

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.
Title: Re:Remove Array() by index
Post by: drivehappy on March 24, 2004, 11:30 AM
What is a collection, I've always used arrays within VB. Are they much like linked lists?
Title: Re:Remove Array() by index
Post by: Adron on March 24, 2004, 11:56 AM
Quote from: drivehappy on March 24, 2004, 11:30 AM
What is a collection, I've always used arrays within VB. Are they much like linked lists?

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.
Title: Re:Remove Array() by index
Post by: o.OV on March 24, 2004, 01:23 PM
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



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



Add-On:
I was expecting command_3 to take less then 10 seconds. Any ideas?
Title: Re:Remove Array() by index
Post by: Adron on March 24, 2004, 01:38 PM
Quote from: o.OV on March 24, 2004, 01:23 PM
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?

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?
Title: Re:Remove Array() by index
Post by: o.OV on March 24, 2004, 01:50 PM
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.
Title: Re:Remove Array() by index
Post by: o.OV on March 25, 2004, 02:13 AM
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



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

Title: Re:Remove Array() by index
Post by: CrAz3D on March 25, 2004, 10:11 AM
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


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?
Title: Re:Remove Array() by index
Post by: Stealth on March 25, 2004, 02:04 PM
Creates a set of sample data for use in testing the speed of the array/collection.
Title: Re:Remove Array() by index
Post by: CrAz3D on March 25, 2004, 02:43 PM
Oh, heh.  Silly me.  Thanks
Title: Re:Remove Array() by index
Post by: Adron on March 25, 2004, 05:31 PM
Quote from: o.OV on March 25, 2004, 02:13 AM
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

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.
Title: Re:Remove Array() by index
Post by: o.OV on March 26, 2004, 03:20 AM
Quote from: Adron on March 25, 2004, 05:31 PM
Quote from: o.OV on March 25, 2004, 02:13 AM
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

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.

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?
Title: Re:Remove Array() by index
Post by: Adron on March 26, 2004, 10:43 AM
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.
Title: Re:Remove Array() by index
Post by: CrAz3D on March 26, 2004, 01:24 PM
QuoteNative 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

All seem to work for me

(com4 is o.Ov's)
Title: Re:Remove Array() by index
Post by: Adron on March 26, 2004, 02:15 PM
Hmmk, so, the odd results are o.OV's. Now I wonder why he's getting so bad results for collections...
Title: Re:Remove Array() by index
Post by: o.OV on March 26, 2004, 10:06 PM
*gives computer a mean kick*  >:(

I'm gonna go check MSDN for anything relevant to my odd results.
Title: Re:Remove Array() by index
Post by: drivehappy on March 27, 2004, 02:31 AM
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.