Alright, so let's assume we have a Dictionary, "myDict" that contains all the initial stuff.(i.e. a Dictionary('Barney'->'Betty' 'Fred'->'Wilma' 'George'->'Martha' 'Ozzie'->'Harriet' ) ).
keysDo: will NOT work for the same reson that i mentioned below Rocky's example. you ABSOLUTELY CAN'T expect to be able to chage an object while you are iterating though it becuase you don't know internally how that iteration is implemented (ie sychnronized or not). Jason Fulghum
I think the previous code needs a little adjustment. Let's say one key/value pair was 'Wilma'->'Wilma'. It would be added and then immediately removed. Here is a small modification that should fix the problem.
myDict keysAndValuesDo: [:k :v | myDict removeKey: k. myDict at: v put: k. ].
i just tried this in squeak and it doesn't work correctly. If you try it, you will see that only half of the names are switched. I think this is because of the implementation of the keysAndValuesDo method. You have the same problem in Java when you try to modify and enumerator while it's in the process of enumerating. it gets confused because it's elements are moving around while it's trying to step through them.
"Here is my answer"
d keys do: [:key | | element | element _ d at: key. d keysAndValuesRemove: [:tKey :value | tKey == key]. d at: element put: key.].
Here is the commend for keysAndValuesRemove, it helps explain much:
keysAndValuesRemove: keyValueBlock
"Removes all entries for which keyValueBlock returns true."
"When removing many items, you must not do it while iterating over the dictionary, since it may be changing. This method takes care of tallying the removals in a first pass, and then performing all the deletions afterward. Many places in the sytem could be simplified by using this method."
There may be a more efficient way to answer this problem, but this avoids a major problem with dictionaries. Deleting is tricky. If you iterate with keysAndValuesDo to delete items, you may be faced with a constantly changing collection to work from. Therefore, I have adopted the strategy of working with the collection of keys and using keysAndValuesRemove.
Has anyone thought about the following dictionary?
Key
Value
Jane
Smith
Joe
Smith
John
Timberland
Michael
Kovak
Tony
Smith
The transpose doesn't work right, because the dictionary associates one and only one key to every entry. If the value is not unique than a transpose of the dictionary is not possible.
Key
Value
Smith
Jane
Smith
Joe
Smith
Tony
Kovak
Michael
Timberland
John
is not possible in a dictionary (because unique keys are required)...
That doesn't stop our program though. We get "undefined behavior". We loose entries... Unknown Assailant
I just have to ask what is the act point of trying to do this in one line of code? Won't the VM run say 3 lines writen efficently at the same speed since it does the thing. It just doesn't seem to gain any optimization. Am I wrong? Robert Schierholz
I think this is a pretty straightforward way of doing it rather than using obscure methods, just a simple swap:
d keys do: [:key | temp := d at: key. d removeKey: key. d at: temp put: key]. Ken Edwards
Or better yet:
d keys do: [:key | d at: (d at: key) put: key. d removeKey: key]. Ken Edwards
Or best (truly in one line, only one period):
d keys do: [:key | d removeKey: (d at: (d at: key) put: key)]. Ken Edwards
"make values keys, make keys values, then remove old keys..."
d keysDo:[:key | d at:(d at:key) put:key. d removeKey:key].