By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
458,127 Members | 1,343 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 458,127 IT Pros & Developers. It's quick & easy.

Enumerate and modify a dictionary

P: n/a
Hi all,

I'm trying to do something that should be really easy, but I can't think of an
obvious way to do it. I have a dictionary whose value is a "value type" (as
opposed to a reference type -- in this case, a Boolean):

Dim dic As New Dictionary(Of Int32, Boolean)
dic(123) = True

I want to set all of the existing entries in the dictionary to False. The
obvious solution:

For Each value As Boolean In dic.Values
value = False
Next

does not set the dictionary values to False as one would expect. Rather, this
code gets a temp variable named value and sets that temp variable to false,
leaving the dictionary value unchanged.

Ok, so I try this code:

For Each key As Int32 In dic.Keys
dic(key) = False
Next

That gets me the dreaded "Collection was modified; enumeration operation may not
execute."

So, how can I set all of the Boolean values in this dictionary to False?

TIA - Bob
Jul 1 '08 #1
Share this Question
Share on Google+
8 Replies


P: n/a
It seems to me that you should just check if the dictionary does not contain
the key, assume false. You should not need to fill the dictionary with
every possibility.

dict.ContainsKey(123), for example.
"Bob Altman" <rd*@nospam.nospamwrote in message
news:er**************@TK2MSFTNGP04.phx.gbl...
Hi all,

I'm trying to do something that should be really easy, but I can't think
of an obvious way to do it. I have a dictionary whose value is a "value
type" (as opposed to a reference type -- in this case, a Boolean):

Dim dic As New Dictionary(Of Int32, Boolean)
dic(123) = True

I want to set all of the existing entries in the dictionary to False. The
obvious solution:

For Each value As Boolean In dic.Values
value = False
Next

does not set the dictionary values to False as one would expect. Rather,
this code gets a temp variable named value and sets that temp variable to
false, leaving the dictionary value unchanged.

Ok, so I try this code:

For Each key As Int32 In dic.Keys
dic(key) = False
Next

That gets me the dreaded "Collection was modified; enumeration operation
may not execute."

So, how can I set all of the Boolean values in this dictionary to False?

TIA - Bob
Jul 1 '08 #2

P: n/a
Bob,

While we're wating for the elegant solution, here's abrute force solution:

Dim myKeysArray(dic.Keys.Count - 1) As Integer
dic.Keys.CopyTo(myKeysArray, 0)

For Each key As Integer In myKeysArray
dic(key) = False
Next

Kerry Moorman
"Bob Altman" wrote:
Hi all,

I'm trying to do something that should be really easy, but I can't think of an
obvious way to do it. I have a dictionary whose value is a "value type" (as
opposed to a reference type -- in this case, a Boolean):

Dim dic As New Dictionary(Of Int32, Boolean)
dic(123) = True

I want to set all of the existing entries in the dictionary to False. The
obvious solution:

For Each value As Boolean In dic.Values
value = False
Next

does not set the dictionary values to False as one would expect. Rather, this
code gets a temp variable named value and sets that temp variable to false,
leaving the dictionary value unchanged.

Ok, so I try this code:

For Each key As Int32 In dic.Keys
dic(key) = False
Next

That gets me the dreaded "Collection was modified; enumeration operation may not
execute."

So, how can I set all of the Boolean values in this dictionary to False?

TIA - Bob
Jul 1 '08 #3

P: n/a
"Bob Altman" <rd*@nospam.nospamschrieb
So, how can I set all of the Boolean values in this dictionary to
False?
For Each key In dic.Keys.ToArray
dic(key) = False
Next

Armin
Jul 1 '08 #4

P: n/a
On 2008-07-01, Bob Altman <rd*@nospam.nospamwrote:
Hi all,

I'm trying to do something that should be really easy, but I can't think of an
obvious way to do it. I have a dictionary whose value is a "value type" (as
opposed to a reference type -- in this case, a Boolean):

Dim dic As New Dictionary(Of Int32, Boolean)
dic(123) = True

I want to set all of the existing entries in the dictionary to False. The
obvious solution:

For Each value As Boolean In dic.Values
value = False
Next

does not set the dictionary values to False as one would expect.
Just a small comment, since you have received a solution - but, the observed
behavior is EXACTLY what is to be expected... Booleans are value types - and
so on any assignment, a copy is made. It's basically the same as:

Dim b1 As Boolean = True
Dim b2 As Boolean = b1

Console.WriteLine ("b1 = {0}, b2={1}", b1, b2)
b1 = False
Console.WriteLine ("b1 = {0}, b2={1}", b1, b2)

--
Tom Shelton
Jul 1 '08 #5

P: n/a
While we're waiting for the elegant solution, here's a brute force solution:
>
Dim myKeysArray(dic.Keys.Count - 1) As Integer
dic.Keys.CopyTo(myKeysArray, 0)

For Each key As Integer In myKeysArray
dic(key) = False
Next

Kerry Moorman
Thanks Kerry. I didn't notice that the KeyCollection had a CopyTo function.

I wrote a little app to test the performance of your solution vs. creating a new
Dictionary and populating it with the keys from the old dictionary and values of
False, like this:

' Fabricate a new Dictionary with keys
' from the old Dictionary
Dim newDic As New Dictionary(Of Int32, Boolean)
For Each kvp As KeyValuePair(Of Int32, Boolean) In dic
newDic(kvp.Key) = False
Next

' Replace the old Dictionary with the new one
dic = newDic

It turns out that creating a new dictionary is *much* faster. In my test app
(shown below) I repeat the code that sets the Dictionary entries to False 10,000
times. The algorithm that copies the keys array takes around 700 ms, which the
algorithm that creates a new dictionary only takes about 100 ms. Both
algorithms leave some garbage behind for the GC to collect, and I can't think of
an easy way to measure that part of the performance.

Bob

--- Code ---

Public Class Form1

Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
' Initialize the Dictionary
Dim dic As New Dictionary(Of Int32, Boolean)

For i As Int32 = 1 To 1000
dic(CInt(Rnd() * 10000)) = True
Next

Dim t1 As DateTime = Now

For i As Int32 = 1 To 10000

' Kerry's algorithm
Dim keys(dic.Count - 1) As Int32
dic.Keys.CopyTo(keys, 0)
For Each key As Int32 In keys
dic(key) = False
Next
Next

Dim t2 As Date = Now
Label1.Text = (t2 - t1).Milliseconds.ToString
End Sub

Private Sub Button2_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
' Initialize the Dictionary
Dim dic As New Dictionary(Of Int32, Boolean)

For i As Int32 = 1 To 1000
dic(CInt(Rnd() * 10000)) = True
Next

Dim t1 As DateTime = Now

For i As Int32 = 1 To 10000
' Bob's algorithm
Dim newDic As New Dictionary(Of Int32, Boolean)
For Each kvp As KeyValuePair(Of Int32, Boolean) In dic
newDic(kvp.Key) = False
Next

dic = newDic
Next

Dim t2 As Date = Now
Label1.Text = (t2 - t1).Milliseconds.ToString

End Sub
End Class
Jul 1 '08 #6

P: n/a
Bob Altman wrote:
>
I wrote a little app to test the performance of your solution vs.
creating a new Dictionary and populating it with the keys from the
old dictionary and values of False, like this:
(snip)
It turns out that creating a new dictionary is *much* faster. In my
test app (shown below) I repeat the code that sets the Dictionary
entries to False 10,000 times. The algorithm that copies the keys
array takes around 700 ms, which the algorithm that creates a new
dictionary only takes about 100 ms. Both algorithms leave some
garbage behind for the GC to collect, and I can't think of an easy
way to measure that part of the performance.
Label1.Text = (t2 - t1).Milliseconds.ToString
(snip)
Label1.Text = (t2 - t1).Milliseconds.ToString
Whoops! Better make that TotalMilliseconds, if you want the actual times, not
just the fractional part of a second. :)

On my machine, "Bob's Algorithm" takes about 4 times longer, just over 3
seconds, to complete.

You might be interested in seeing what happens if you create a class to hold
your Boolean, and use objects in the dictionary instead of value types. On my
machine, it beats both methods.

Private Class MyBool
Public TheBool As Boolean
Public Sub New()
TheBool = False
End Sub
Public Sub New(ByVal Init As Boolean)
TheBool = Init
End Sub
End Class

Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click

Dim dic As New Dictionary(Of Int32, MyBool)

For i As Int32 = 1 To 1000
dic(CInt(Rnd() * 10000)) = New MyBool(True)
Next

Dim t1 As DateTime = Now

For i As Int32 = 1 To 10000
For Each b As MyBool In dic.Values
b.TheBool = False
Next
Next

Dim t2 As Date = Now
Label1.Text = (t2 - t1).TotalMilliseconds.ToString

End Sub

Jul 2 '08 #7

P: n/a
> Label1.Text = (t2 - t1).Milliseconds.ToString
>
Whoops! Better make that TotalMilliseconds, if you want the actual times,
not just the fractional part of a second. :)
Ouch! It's amazing how many ways there are to write subtly wrong code. The
funny part is that it sure seemed to me that it took a lot longer than 1
second to complete (uh, more like 3 seconds)...
On my machine, "Bob's Algorithm" takes about 4 times longer, just over 3
seconds, to complete.

You might be interested in seeing what happens if you create a class to
hold your Boolean, and use objects in the dictionary instead of value
types.
That was actually the first thing I tried, since intuition tells me that it
would be a lot faster to just write to a Boolean field rather than replacing
the entire Dictionary entry. But I gave up when I discovered that I use the
ContainsValue method on the dictionary

If dic.ContainsValue(False) Then <do something>

and I didn't want to figure out how to either implement some arcane
interface or write my own "search through the darned thing" routine to get
that to work. But as long as I'm actually doing some performance testing, I
guess I really should try that and see how it compares. (Maybe if I'm lucky
I'll come back tomorrow morning -- it's 10:40 PM in Southern California
right now -- and someone will run that test and post the results.)

Bob

Jul 2 '08 #8

P: n/a
Hi Bob,

Regarding on the performance of the two methods you've considered so far:

1. copy keys to array and modify the original collection

2. not copy keys but directly create a new dictionary

Here are some of my understanding and suggetion:

** For the performance, it depend on what's the critical point of the
execution. For the two approaches here:

1. copy keys approach's critical point is copying all the keys from
dictionary to an key array

2. creating new dictionary's critical point is creating the new dictonary
and also all the objects in it.

Here in your case, the object is simply a boolean value, therefore, I
think the overhead of copying keys into array (in #1 ) will contribute to
the most performance overhead. However, if the stored objects are large
complex class object, I think the creating new dictionary approach will be
overkilled by creating every new objects in the original dictionary.

Therefore, you can decide which approach to use depend on the actual
screnario.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead
Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
ms****@microsoft.com.

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscripti...ult.aspx#notif
ications.

==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.

--------------------
>From: "Bob Altman" <rd*@nospam.nospam>
References: <er**************@TK2MSFTNGP04.phx.gbl>
<A3**********************************@microsoft.co m>
>Subject: Re: Enumerate and modify a dictionary
Date: Tue, 1 Jul 2008 16:46:21 -0700
b
>
>While we're waiting for the elegant solution, here's a brute force
solution:
>>
Dim myKeysArray(dic.Keys.Count - 1) As Integer
dic.Keys.CopyTo(myKeysArray, 0)

For Each key As Integer In myKeysArray
dic(key) = False
Next

Kerry Moorman

Thanks Kerry. I didn't notice that the KeyCollection had a CopyTo
function.
>
I wrote a little app to test the performance of your solution vs. creating
a new
>Dictionary and populating it with the keys from the old dictionary and
values of
>False, like this:

' Fabricate a new Dictionary with keys
' from the old Dictionary
Dim newDic As New Dictionary(Of Int32, Boolean)
For Each kvp As KeyValuePair(Of Int32, Boolean) In dic
newDic(kvp.Key) = False
Next

' Replace the old Dictionary with the new one
dic = newDic

It turns out that creating a new dictionary is *much* faster. In my test
app
>(shown below) I repeat the code that sets the Dictionary entries to False
10,000
>times. The algorithm that copies the keys array takes around 700 ms,
which the
>algorithm that creates a new dictionary only takes about 100 ms. Both
algorithms leave some garbage behind for the GC to collect, and I can't
think of
>an easy way to measure that part of the performance.

Bob
Jul 2 '08 #9

This discussion thread is closed

Replies have been disabled for this discussion.