How best to handle array element removal? 2023R4

Hello all,

I have an array of a subclassed URLConnection. In a class called clsNotify, a new instance is created. During that process, I pass to it the array index along with some other info.

When the URLConnection is finished, I call a method in clsNotify to Array.RemoveAt(Index). I do this since clsNotify is the owner of the array.

The problem comes in when after removing an array index, all of the indexes are change so there are no empty indexes. So if 5 URLConnection instances are created (index 0-4) and say any one of them is removed, how to know what index the remaining instance(s) are?

Would appreciate any direction on this please.

Thank you,
Tim

Iterate the array and use IS to see if that instance of clsNotify is the same as what you pass in (i.e. the one you want to remove).

1 Like

Hi Bob,

Thank you!

For i As integer = 0 to URLs.LastIndex
  If URLs(i) is URLs(Idx) Then
    URLs().Remove(i)
  End If
Next i

The code above does appear to work. Much appreciate your feedback!
Tim

Nope - you’ll run into problems with that. You have to scan the array from URLs.LastIndex DownTo 0, or else you’ll miss some of them:

For i As integer = URLs.LastIndex DownTo 0
  If URLs(i) is URLs(Idx) Then
    URLs().Remove(i)
  End If
Next i
2 Likes

Why do you need to loop if you already know the value of IDX. Can you not simply:

URLs.RemoveAt(Idx)

if URLs(Idx) is a string (or some other type) passed in then it should read something like:

For i As integer = 0 to URLs.LastIndex
  If URLs(i) is ThisURL Then
    URLs.RemoveAt(i)
    Exit For // Stop looking now we have found it
  End If
Next i

So you stop looking after you find it. Then it doesn’t matter if you go upwards or downwards. If it can match more than one, the yes it is imperative that you use “LastIndex DownTo 0” as the indexes will shrink when the first Remove takes place, the for loop will then skit the next value.

Hi Ian,

Thanks for the tips!
Tim

So your calling code should pass in Self and the code should be like my ThisURL version above. Using URLs(Idx) inside the function isn’t going to work more than once. The “Exit For” will prevent the loop going crazy when the item is removed.

1 Like

I see what you are saying, however this code fails when the Idx value is a 3 (for example) and array is down to only Element 0…

For i As integer = URLs.LastIndex DownTo 0
  If URLs(i) is URLs(Idx) Then
    URL().Remove(i)
    Exit For
  End If
Next i

So it appears that using DownTo 0 causes some pain. Or am I missing something?

However the same thing happens without DownTo…

There’s got to be a better way!

Tim

Yes, don’t even store which number you think is the one for this URL. Do something like:

Sub SomeEventOnAGivenURL
   // Time to Die
   RemoveURL( Self )
End Sub

Sub RemoveURL( ThisURL as URL )
   For i As integer = URLs.LastIndex DownTo 0
      If URLs(i) is ThisURL Then
          URLs.RemoveAt(i)
          Exit For
      End If
   Next i
End Sub

Passing in the URL to be removed means you don’t need to know which number it was in the array. The loop will find it for you and remove it.

The “SomeEventOnAGivenURL” reference is which ever event on the URL class detects that it is time to close and do away with the given URL.

Thought of that last week… but thought there might be a more elegant / preferred method.
I’ll give it a try!
Tim

If you are using an array to hold the URLs then that’s the best way. You could use a dictionary to hold them, with an Index as the Key and the value as the URL instance. When you remove the Key/value pair the indices of the other dictionary elements doesn’t change, but that’s more complicated.

If there are 1000s of URLs then the dictionary will be faster. Otherwise you likely won’t notice.

Well, theoretically this would work assuming you only ever have each instance in the array once, but if the object has already been removed then you’ll get an exception.

URLs.RemoveAt(URLs.IndexOf(ThisURL)

So you could break it up.

var index as Integer = URLs.IndexOf(ThisURL)
if index >= 0 then URLs.RemoveAt(index)

That’s how I’d write it.

1 Like

Yes, that would work and likely be faster. Internally IndexOf is doing the loop we have created by hand.

Well, now there a new issue.
When I add ThisURL As URL to the remove, the IDE will not accept that. So I guess it needs to be something like URLs.URL?

Confusion taking over!

The issue, and one that I did not clarify, is that these are for Twilio - so separate Twilio request being sent. There is no distinct URL to it since all instances will use the same URL but will have different messages

Tim

I think we’re all assuming (or it could just be me) that your array is defined as:
URLs() as URLConnection
And ThisURL is of type URLConnection.

URLConnection or some subclass.

Is that not the case?

No that is not correct. I used URL as a shorthand for what ever class your array is holding. I seem to remember that it is a URLConnection, so it should read:

Sub RemoveURL( ThisURL as URLConnection )
//...

Or what ever sub class you have used.

The calling method should pass in the URLConnection to be removed. Which may or may not be Self.

That is the case Anthony
Tim

But there will be a distinct URLConnection object for each one, yes? If so it should all work fine, no matter what the actual url string is “https://…” isn’t being tested against. It is the object itself.

Then you can simply do something like:

Public Sub Remove(socket as URLConnection)
  var index as Integer = URLs.IndexOf(socket)
  if index >= 0 then URLs.RemoveAt(index)
End Sub

Yes, it seems to all work as expected now.
Thank you all again! I really appreciate your help.

Tim

2 Likes