I have an object like a Dictionary('CMFireAutomataModel'->a Dictionary('nbAshes'->193 'nbFires'->851 ) ) and I would like to have something like Dictionary('nbAshes'->193 'nbFires'->851 ).
I don't know how to "unstack" the first dictionary.
Let's say you have a Dictionary whose keys are Strings and its values are Numbers or Dictionaries of the same sort (i.e., with keys that are strings and values that are dicts or numbers). What we want is a way to "promote" or "unstack" all string keys and numbers to the mother dictionary.
unstack: aDictionary
| dict |
dict := aDictionary class new.
aDictionary keysAndValuesDo: [:k :v | | d |
v isNumber
ifTrue: [dict at: k put: v]
ifFalse: [
d := self unstack: v.
dict addAll: d associations]].
^dict
Note that I've used aDictionary class new to make sure the method answers with a Dictionary of the same kind (e.g., an IdentityDictionary, etc.).
Note also that the method could go in any class. I haven't put it in Dictionary because I don't think this is general enough (even though that would have simplified the code a little bit)
Related
Is there a standard method for removing duplicate entries in an array, but preserving the order?
e.g.
#(c a b a a b) withoutDuplicates "-> #(c a b)"
I used to use removeDuplicates, but apparently that's an extension method added by Roassal (so I cannot always use it)
Written by hand, the best solution (I have) is
a := #(c a b a a b).
d := OrderedDictionary new.
a do: [ :each | d at: each put: true ].
d keys. "-> #(c a b)"
But is there a standard way?
Same as yours but shorter in terms of text to type, not performance.
(#(c a f b c a d c a e f f) collect: [ :e | e -> true ]) asOrderedDictionary keys
Your solution looks very good to me. Here is another one:
withoutDuplicates
| visited |
visited := Set new.
^self select: [:element |
(visited includes: element) not
ifTrue: [visited add: element];
yourself]
This one is more verbose but uses (only) one additional collection: the visited set. An OrderedDictionary, on the other hand, has two internal collections a Dictionary and the sequence of orderedKeys. If you are not concerned with space I would suggest using your solution.
As an aside note I would say that the use of #yourself here is a bit unusual. It follows the pattern:
^boolean ifTrue: [self doThis]; yourself
Which has a side effect (self doThis) when boolean is true and answers with boolean in either case. Most people would write it as:
boolean ifTrue: [self doThis].
^boolean
but this requires the addition of a block temporary because in our case boolean refers to the expression (visited includes: element) not which we shouldn't repeat.
OR...
... you could take this opportunity to implement OrderedSet in Pharo...
I have a given dictionary and want to map it to an object of a specific class.
All keys of the dictionary should be mapped to equally named instance variables of the object.
I guess this is a common procedure? What is the common way to accomplish it?
Consider doing something like this:
dict := { #x -> 5 . #y -> 6 } asDictionary. "dictionary as you described"
basicObj := Point basicNew. "basic instance of your object"
dict keysAndValuesDo: [ :key :val |
basicObj instVarNamed: key put: val ].
^ basicObj
This is indeed a common pattern. It is often used in serialization and materialization. You can find an implementation in
STON
| dict |
dict := #{'foo'->'brown'. 'bar'->'yellow'.
'qix'->'white'. 'baz'->'red'. 'flub'->'green'} asDictionary.
dict at: 'qix'
If I PrintIt, I get 'white'. If I remove 'asDictionary', I still get 'white'. What does a dictionary give me that a collection of associations doesn't?
Expression like #{exp1 . sxp2 . exp3} is amber-smalltalkspecific and creates a HashedCollection, which is a special kind of dictionary where keys are strings (probably in Javascript you use things like this a lot).
In other smalltalks there is no expression like that. Instead array expressions which look like: {exp1 . sxp2 . exp3} (there is no leading #) were introduced in squeak and are also available in pharo (which is a fork of Squeak) and Amber. Now the array expression creates an Array and so you have to use integers for #at: message. For example dict at: 2 will return you an association 'bar'->'yellow' because it is on the second position of the array you've created.
#asDictionary is a method of a collection that converts it into a dictionary given that the elements of the collection are associations. So if you want to create a dictionary with keys other than strings, you can do it like this:
dict := {
'foo' -> 'brown' .
1 -> 'yellow' .
3 # 4 -> 'white' .
#(1 2) -> 'red' } asDictionary
A Dictionary is a collection of Associations. It is, in fact, Smalltalk's canonical collection of Associations. (An instance of the Association Class is a key value pair, where the value can be an object of any Class).
The advantage a Dictionary gives you is that it has specialised methods for dealing with Associations, compared to other Collections you might be tempted to use.
A Dictionary provides:
removeKey: aKey . removes aKey
includesKey: aKey . checks for the existence of the key
includes: aValue . checks for the existence of a value
at:put: . shorthand for
anAssociation := Association key:value: .
aDictionary add:
e.g.
anAssociation := Association key: 'Hello'
value: 'A greeting people often use' .
aDictionary add: anAssociation .
If the key already exists in the Dictionary, then at:put will overwrite the pre-existing value with the new value, so it's important to check and make sure that the key has a unique value when adding new items.
Both the key and the value can be an object instance of any Class. Every Association in a Dictionary can be any kind of object, and every single key and value might be a instance of a different Class of object from every other element in the Dictionary.
You can create an Association by
anAssociation := Association key: 'keyOfElement' value: 'valueOfElement'
or, more succinctly,
anAssociation := 'keyOfElement' -> 'valueOfElement'
If you want to use keys entirely made specifically of Symbols, there is also the Class IdentityDictionary
I've got a Dictionary like this:
a PluggableDictionary(
Rankable1->8.5
Rankable2->9.0
)
I need just an OrderedCollection with the Rankable objects in descending order:
a OrderedCollection(
Rankable2
Rankable1
)
I noticed it is easy to sort by keys, but I found it a bit more difficult to sort by values. What is the smalltalk way of doing this?
If you need one shot sorted collection in noncritical loop you might use something like this (uses pharo syntax to initialize example dictionary):
pd := PluggableDictionary newFromPairs: { 'a' . 2 . 'b' . 1 . 'c' . 3} .
(pd associations asSortedCollection: [:x :y | x value < y value])
collect: [:assoc | assoc key].
If you would need it more often, than you might consider introducing your own class that will keep this collection calculated.
If you're using VisualWorks, you can take advantage of SortFunction and Symbol>>value behavior to reduce all of that down to
(aDictionary associations sort: #value ascending) collect: #key
If you can use Grease (eg, when using Seaside), you can
probably use its GROrderedMultiMap. It is intended for small dictionaries with probably multiple values per key.
On a second note, probably you can swap key and value, and just send #asSortedCollection, like this:
(Dictionary newFrom: { 2 -> 'b' . 1-> 'a' })
asSortedCollection "--> a SortedCollection('a' 'b')"
(Tested in Squeak and Pharo)
Got it:
^ ((SortedCollection sortBlock:
[:association :otherAssociation | association value > otherAssociation value])
addAll: theDictionary associations;
yourself) collect: [:association | association key]
I have the following structure of a dictionary in Erlang:
Key: {element_name, a, element_type, type_1}
Value: [list].
Dictionary: (({element_name, a, element_type, type_1},[List]), ({element_name, b, element_type, type_2},[List])).
I would like to update a certain key-value pair and insert some new data into the 'key' tuple (not into 'value' list):
1. Value_list = dict:fetch({element_name, a, element_type, _}, Dict).
2. Dict2 = dict:erase ({element_name, a, element_type, _}, Dict).
3. Dict3 = dict:store ({element_name, a, element_type, New_type}, Value_list, Dict2).
The problem is that at line 1 Erlang says that variable "_" is unbound.
It seems that I cannot fetch a value by providing only a part of the key if the key is a tuple. Is this true?
Is it actually possible to update a key in a dictionary?
Is there any shorter way to do this instead of doing 1,2 and 3?
dict doesn't support what you want to do. you will have to know the key, erase the old key/value pair, and store a new one.
take a look at ets. you can use ets:match to find keys that match your spec. you'll still have to delete the old key/value pair and insert a new one.
If you insist on updating the Key in the dictionary without deleting it and later storing a new value against it, i suggest that you first convert your Dict into a list by this: dict:to_list/1. Consider this piece of code:
Fun_to_match_key = fun({{element_name, a, element_type, _} = Key,Value})->
%% do some stuff here with the Key and value and assuming
%% this fun returns the new Key-Value pair you want
New_Key = update_my_key(Key),
New_Value = update_my_value_if_need_to(Value),
{New_Key,New_Value};
(Any)-> Any
end,
%% Then in one operation, you convert the dict into a list, apply the
%% fun above in a list comprehension and convert the list back to a dict
New_dict = dict:from_list([Fun_to_match_key(Key_Value_Pair) || Key_Value_Pair <- dict:to_list(Old_Dict)]),
New_dict.
Converting the dict into a list will give you a proplist() which is much easier to manipulate either Key or value. You could use any method say, recursion with several clauses in which you pattern match the nature of Key you want to manipulate, in the above example i have chosen to use a fun within a list comprehension.
That should do the trick!