Iterating through a HashTable

G

Guest

I have a hashtable keyed by some name, holding an instance of an object. Most
of the time I use the hashtable in the traditional sense, given a name, I
lookup the object, then I run a method on that object. Occaisionally however
I need to run a method on every object in the hashtable. I've done both
For..Each and iEnumeratior loops. The messy part is that under certain
conditions, while iterating, a condition exists where I need to remove an
object from the hashtable. With ArrayLists I handle this with a reverse
iteration (from last to first) and do a .RemoveAt. Hashtables do not have
..RemoveAt. For..Each doesnt work because .Remove needs the key and I only
have the object, iEnumerator doesn't work because I get an error after the
first .Remove saying my enumerator is now invalid, so I can't continue that
iteration.

I've thought about several solutions mostly inlvolving separate threads, but
wanted to know if there was a cleaner way to handle this. Anyone come across
this? It seems like a fairly standard problem, there must be some "pattern"
solution.
-Ken
 
J

Jonas Pohlandt

Try making a copy of the keys collection if it isn't too expensive.

Dim h As New Hashtable
Dim key, value As Object
Dim keys As ICollection = h.Keys
For Each key In keys
value = h(key)
If value.condition Then
h.Remove(key)
End If
Next

HTH
 
J

Jonas Pohlandt

Uuhm... maybe actually making a copy would help.

Dim key, value As Object
Dim keys As ICollection = h.Keys
Dim keylist As New ArrayList
keylist.AddRange(keys)
For Each key In keylist
If CInt(key) > 5 Then
h.Remove(key)
End If
Next
 
C

Cor Ligthert

Ken,

I have the idea that you are not iterating through the keys of the
hasthtable but throught the values.

In my idea is that not where the hashtable is not made for, in that case by
instance the datatable does a much better job as collection because you have
much more methods to get the values from the objects in the datarow and
remove when needed those rows.

However maybe I see something wrong?

Cor
 
G

Guest

I've considered the copy solution, but given that I don't know in advance my
max item count, there'd be this potential baggage hanging over my head of a
duplicate collection. Also, because I'm using the 'value' side of the
hashtable, then based on some state need to delete it, I can't quite get the
logic in place even using a copy.

My solution so far is to do my iteration with a SyncLock wrapper and spawn a
separate thread for each 'Remove', then .NET will handle the blocking for me,
and the removes will occur after the iteration pass is complete. Or build an
array list of keys to delete as i'm iterating, and do a second for loop pass
 
G

Guest

Well, I simplified my model for brevity. What I have is more complicated but
boils down to a hash table of open TCP sockets with the key being some
internal identifier. Normal processing is, given an identifier, I do
mySocket = myHashTable(identifier)
mySocket.send("blah")
again, this is simplified for example sake. it's not really like this there
is a lot of async calls and callbacks etc. Now, if I check and mySocket is
not connected, or if i get an error back from .send, I shutdown that socket
and remove it from the hashtable. When processing one at a time, this works
fine.

My problem is that there is one instance where I have to loop through the
entire hash table of sockets and do a .Send. In that instance, if i have a
bad socket and want to remove it from the Hashtable...i get the problem i
originally described. So, databases, etc. don't fit my problem domain.

-Ken
 
G

Guest

Well, I simplified my model for brevity. What I have is more complicated but
boils down to a hash table of open TCP sockets with the key being some
internal identifier. Normal processing is, given an identifier, I do
mySocket = myHashTable(identifier)
mySocket.send("blah")
again, this is simplified for example sake. it's not really like this there
is a lot of async calls and callbacks etc. Now, if I check and mySocket is
not connected, or if i get an error back from .send, I shutdown that socket
and remove it from the hashtable. When processing one at a time, this works
fine.

My problem is that there is one instance where I have to loop through the
entire hash table of sockets and do a .Send. In that instance, if i have a
bad socket and want to remove it from the Hashtable...i get the problem i
originally described. So, databases, etc. don't fit my problem domain.

-Ken
 
G

Guest

Well, I simplified my model for brevity. What I have is more complicated but
boils down to a hash table of open TCP sockets with the key being some
internal identifier. Normal processing is, given an identifier, I do
mySocket = myHashTable(identifier)
mySocket.send("blah")
again, this is simplified for example sake. it's not really like this there
is a lot of async calls and callbacks etc. Now, if I check and mySocket is
not connected, or if i get an error back from .send, I shutdown that socket
and remove it from the hashtable. When processing one at a time, this works
fine.

My problem is that there is one instance where I have to loop through the
entire hash table of sockets and do a .Send. In that instance, if i have a
bad socket and want to remove it from the Hashtable...i get the problem i
originally described. So, databases, etc. don't fit my problem domain.

-Ken
 
J

Jay B. Harlow [MVP - Outlook]

Ken,
If my routine normally wanted to remove a minority of the entries, I would
consider using a For Each on the HashTable, adding each entry to remove to
an ArrayList. Then when I finished the HashTable I would use a For Each on
the ArrayList removing each item from the HashTable.

If my normally wanted to remove a majority of the entries, I would consider
using a For Each on the HashTable, adding each entry to save to a new
HashTable. Then when I finished I would replace the old hash table with the
new hashtable. Alternatively I might Clone the HashTable, clear the original
& For Each on the Clone...

I have used variations of Jonas's idea also.

Hope this helps
Jay
 
G

Guest

Interesting, and worth noteing for possible use in the future, but the
problem it solves (being able to iterate through a hashtable in FIFO order)
is not the problem I have, I don't care what order it's in. And at first
blush it looks like the .Remove during an enumeration will have the same
problems that a regular Hashtable has.

Thanks for that though.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top