Hot to retrieve values from Nested Dictionaries
May I ask: What's the idiomatic way to retrieve values from nested dictionaries? (((dict1 at: 'key1') at: 'key2') at: 'key3') Are all the brackets really necessary? BR Mike
On Apr 24, 2017, at 14:42, Markus Böhm <markus.boehm@gmail.com> wrote:
May I ask: What's the idiomatic way to retrieve values from nested dictionaries?
(((dict1 at: 'key1') at: 'key2') at: 'key3')
Are all the brackets really necessary?
I think so, without the parenthesis, it is interpreted as one message at:at:at: If you use it a lot, you may want to convert the dictionary structure into domain objects. Juraj
BR Mike
For these use cases it would be nice to have some sort of syntax sugar as with the cascade operator, but with a chaining operator instead. The chaining operator would send the message to the result of the previous statement instead of the original receiver as in the semicolon cascade operator (;). E.g. dict1 at: 'key1' : at: 'key2' : at: 'key3' . I selected the colon character in the lack of non-message related characters. It's only a daydream and nothing that I found very often needing, except for cases like the mentioned in this thread, extracting a deeply nested value from a JSON object tree/dictionary. ps: use the extra parenthesis, they're not that many. :) Regards! Esteban A. Maringolo 2017-04-24 14:48 GMT-03:00 Juraj Kubelka <juraj.kubelka@icloud.com>:
On Apr 24, 2017, at 14:42, Markus Böhm <markus.boehm@gmail.com> wrote:
May I ask: What's the idiomatic way to retrieve values from nested dictionaries?
(((dict1 at: 'key1') at: 'key2') at: 'key3')
Are all the brackets really necessary?
I think so, without the parenthesis, it is interpreted as one message at:at:at:
If you use it a lot, you may want to convert the dictionary structure into domain objects.
Juraj
BR Mike
Maybe we could introduce `@` message, so one can chain them and then even execute keyword without parenthesis Dictionary>>@ aKey ^ at: aKey dict @ 'key1' @ 'key2' @ 'key3' dict @ 'key1' @ 'key2' @ 'key3' select: [ :each | ... ] I'm always adding this when hacking around, maybe we could have it in Pharo. Peter On Mon, Apr 24, 2017 at 02:48:48PM -0300, Juraj Kubelka wrote:
On Apr 24, 2017, at 14:42, Markus Böhm <markus.boehm@gmail.com> wrote:
May I ask: What's the idiomatic way to retrieve values from nested dictionaries?
(((dict1 at: 'key1') at: 'key2') at: 'key3')
Are all the brackets really necessary?
I think so, without the parenthesis, it is interpreted as one message at:at:at:
If you use it a lot, you may want to convert the dictionary structure into domain objects.
Juraj
BR Mike
Le 24/04/2017 à 19:42, Markus Böhm a écrit :
May I ask: What's the idiomatic way to retrieve values from nested dictionaries?
(((dict1 at: 'key1') at: 'key2') at: 'key3')
Are all the brackets really necessary?
BR Mike
Hi, To know if brackets are necessary you can use the "Format" option in your method. Right click -> format or cmd/alt/ctrl + shift + f In this case you can just write: ((dict1 at: 'key1') at: 'key2') at: 'key3'. -- Cyril Ferlicot https://ferlicot.fr http://www.synectique.eu 2 rue Jacques Prévert 01, 59650 Villeneuve d'ascq France
Tx for advice. P.S.: I got nested dictionaries after JSON API call at wunderground weather API. To see all the response in Pharo inspector "live" is really great :-) BR Mike On Mon, Apr 24, 2017 at 7:51 PM, Cyril Ferlicot D. <cyril.ferlicot@gmail.com
wrote:
Le 24/04/2017 à 19:42, Markus Böhm a écrit :
May I ask: What's the idiomatic way to retrieve values from nested dictionaries?
(((dict1 at: 'key1') at: 'key2') at: 'key3')
Are all the brackets really necessary?
BR Mike
Hi,
To know if brackets are necessary you can use the "Format" option in your method.
Right click -> format
or cmd/alt/ctrl + shift + f
In this case you can just write:
((dict1 at: 'key1') at: 'key2') at: 'key3'.
-- Cyril Ferlicot https://ferlicot.fr
http://www.synectique.eu 2 rue Jacques Prévert 01, 59650 Villeneuve d'ascq France
If you are using NeoJSON you might want to take a look at the NeoJSONObject class. It's basically a Dictionary with "JavaScript" behavior. I.e. you can simply use messages to access keys and non existing keys return nil. Your example can thus be written as: val := dict1 key1 key2 key3. When using NeoJSON you can simply configure your Mapper (Reader/Writer) to use NeoJSONObject using #mapClass: CU, Udo On 24/04/2017 20:04, Markus Böhm wrote:
Tx for advice.
P.S.: I got nested dictionaries after JSON API call at wunderground weather API. To see all the response in Pharo inspector "live" is really great :-)
BR Mike
On Mon, Apr 24, 2017 at 7:51 PM, Cyril Ferlicot D. <cyril.ferlicot@gmail.com <mailto:cyril.ferlicot@gmail.com>> wrote:
Le 24/04/2017 à 19:42, Markus Böhm a écrit : > May I ask: > What's the idiomatic way to retrieve values from nested dictionaries? > > (((dict1 at: 'key1') at: 'key2') at: 'key3') > > Are all the brackets really necessary? > > BR Mike
Hi,
To know if brackets are necessary you can use the "Format" option in your method.
Right click -> format
or cmd/alt/ctrl + shift + f
In this case you can just write:
((dict1 at: 'key1') at: 'key2') at: 'key3'.
-- Cyril Ferlicot https://ferlicot.fr
http://www.synectique.eu 2 rue Jacques Prévert 01, 59650 Villeneuve d'ascq France
On 04/24/2017 11:16 AM, Esteban A. Maringolo wrote:> For these use cases it would be nice to have some sort of syntax sugar
as with the cascade operator, but with a chaining operator instead.
This doesn't even require syntactic sugar, just objects, and this is a more general problem even with a back to back chain of select/detect/reject style things. I solved this for myself years ago by introducing what I call a pipe (nod to unix) allowing me to chain calls in a pipeline without all the parens with each call acting on the result value of the last call. Trivially implemented using #doesNotUnderstand: and the cascade operator. ^ dict1 asPipe at: 'key1'; at: 'key2'; at: 'key3'. Anytime I have a bunch of back to back calls that would require a lot of parens, I just create a pipe... maxRoomsAvailable ^self findBlocks asPipe select: [ :e | e blockDate between: actualCheckInDate and: actualCheckInDate + (nights - 1) days ]; detectMin: [ :e | e quantityAvailable ]; quantityAvailable The simplest implementation is... Object>>asPipe ^ SPipe with: self Object subclass: #SPipe instanceVariableNames: 'value' classVariableNames: '' poolDictionaries: '' category: 'PharoExtensions' privateValue: anObject value := anObject yourself ^ value yourself doesNotUnderstand: aMessage ^ value := value perform: aMessage selector withArguments: aMessage arguments SPipe class>>with: anObject ^ (self new) privateValue: anObject; yourself -- Ramon Leon
2017-04-24 16:10 GMT-03:00 Ramon Leon <ramon.leon@allresnet.com>:
On 04/24/2017 11:16 AM, Esteban A. Maringolo wrote:>
For these use cases it would be nice to have some sort of syntax sugar as with the cascade operator, but with a chaining operator instead.
This doesn't even require syntactic sugar, just objects, and this is a more general problem even with a back to back chain of select/detect/reject style things. I solved this for myself years ago by introducing what I call a pipe (nod to unix) allowing me to chain calls in a pipeline without all the parens with each call acting on the result value of the last call. Trivially implemented using #doesNotUnderstand: and the cascade operator.
^ dict1 asPipe at: 'key1'; at: 'key2'; at: 'key3'.
Anytime I have a bunch of back to back calls that would require a lot of parens, I just create a pipe...
maxRoomsAvailable ^self findBlocks asPipe select: [ :e | e blockDate between: actualCheckInDate and: actualCheckInDate + (nights - 1) days ]; detectMin: [ :e | e quantityAvailable ]; quantityAvailable
Very neat implementation. I think this simple class could come as part of the base image :) Esteban A. Maringolo
Tx, I tried Your proposal. Just as an example, it works: (ZnClient new url: 'http://api.wunderground.com/api/APIKEY/hourly/q/germany/munich.json '; contentReader: [ :entity | (NeoJSONReader on: entity readStream) mapClass: NeoJSONObject; propertyNamesAsSymbols: true; next ]; get ) hourly_forecast collect: [:e | e FCTTIME hour_padded asInteger ] P.S.: Editor in Playground shows NeoJSONObject keys in red color? Am 24.04.2017 9:00 nachm. schrieb "Udo Schneider" < udo.schneider@homeaddress.de>:
If you are using NeoJSON you might want to take a look at the NeoJSONObject class. It's basically a Dictionary with "JavaScript" behavior. I.e. you can simply use messages to access keys and non existing keys return nil. Your example can thus be written as:
val := dict1 key1 key2 key3.
When using NeoJSON you can simply configure your Mapper (Reader/Writer) to use NeoJSONObject using #mapClass:
CU,
Udo
On 24/04/2017 20:04, Markus Böhm wrote:
Tx for advice.
P.S.: I got nested dictionaries after JSON API call at wunderground weather API. To see all the response in Pharo inspector "live" is really great :-)
BR Mike
On Mon, Apr 24, 2017 at 7:51 PM, Cyril Ferlicot D. < cyril.ferlicot@gmail.com <mailto:cyril.ferlicot@gmail.com>> wrote:
Le 24/04/2017 à 19:42, Markus Böhm a écrit : > May I ask: > What's the idiomatic way to retrieve values from nested dictionaries? > > (((dict1 at: 'key1') at: 'key2') at: 'key3') > > Are all the brackets really necessary? > > BR Mike
Hi,
To know if brackets are necessary you can use the "Format" option in your method.
Right click -> format
or cmd/alt/ctrl + shift + f
In this case you can just write:
((dict1 at: 'key1') at: 'key2') at: 'key3'.
-- Cyril Ferlicot https://ferlicot.fr
http://www.synectique.eu 2 rue Jacques Prévert 01, 59650 Villeneuve d'ascq France
2017-04-25 8:49 GMT-03:00 Markus Böhm <markus.boehm@gmail.com>:
Tx, I tried Your proposal. Just as an example, it works:
P.S.: Editor in Playground shows NeoJSONObject keys in red color?
It's highlighted in red because for the playground the keys are selectors not implemented by any class in the image. The key in the Playground is not such, only a trick of NeoJSONObject using Smalltalk's #doesNotUnderstand: mechanism to map selectors to keys. Regards! Esteban A. Maringolo
JsonObject has the doesNotUnderstand: trick too. Esteban A. Maringolo wrote
2017-04-25 8:49 GMT-03:00 Markus Böhm <
markus.boehm@
>:
Tx, I tried Your proposal. Just as an example, it works:
P.S.: Editor in Playground shows NeoJSONObject keys in red color?
It's highlighted in red because for the playground the keys are selectors not implemented by any class in the image.
The key in the Playground is not such, only a trick of NeoJSONObject using Smalltalk's #doesNotUnderstand: mechanism to map selectors to keys.
Regards!
Esteban A. Maringolo
-- View this message in context: http://forum.world.st/Hot-to-retrieve-values-from-Nested-Dictionaries-tp4943... Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
Browsing in Pharo, I found that Dictionary has a subclass KeyedTree, which is in effect a set of nested dictionaries. Retrieval is by quoting a path, which is simply an array of keys. So in your case it would read: dict1 atPath: #(âkey1â âkey2â âkey3â). This might be more efficient than repeated use of the DNU mechanism. It is not clear (to me, at least) how to construct the nested dictionaries as a KeyedTree in the first place, but this might be an alternative approach. Hope this helps Peter Kenny From: Pharo-users [mailto:pharo-users-bounces@lists.pharo.org] On Behalf Of Markus Böhm Sent: 24 April 2017 18:42 To: pharo-users@lists.pharo.org Subject: [Pharo-users] Hot to retrieve values from Nested Dictionaries May I ask: What's the idiomatic way to retrieve values from nested dictionaries? (((dict1 at: 'key1') at: 'key2') at: 'key3') Are all the brackets really necessary? BR Mike
On 26 Apr 2017, at 01:01, PBKResearch <peter@pbkresearch.co.uk> wrote:
Browsing in Pharo, I found that Dictionary has a subclass KeyedTree, which is in effect a set of nested dictionaries. Retrieval is by quoting a path, which is simply an array of keys. So in your case it would read: dict1 atPath: #(âkey1â âkey2â âkey3â). This might be more efficient than repeated use of the DNU mechanism. It is not clear (to me, at least) how to construct the nested dictionaries as a KeyedTree in the first place, but this might be an alternative approach.
I saw this too and I thought it was interesting, hence I added it to NeoJSONObject. Name: Neo-JSON-Core-SvenVanCaekenberghe.40 Author: SvenVanCaekenberghe Time: 26 April 2017, 4:35:49.433269 pm UUID: c336587e-740a-0d00-b51a-dacd0088e41c Ancestors: Neo-JSON-Core-SvenVanCaekenberghe.39 Name: Neo-JSON-Tests-SvenVanCaekenberghe.38 Author: SvenVanCaekenberghe Time: 26 April 2017, 4:36:04.583272 pm UUID: 73623f7f-740a-0d00-b51b-f4000088e41c Ancestors: Neo-JSON-Tests-SvenVanCaekenberghe.37
From the class comment:
Additionally, I support path access for nested instances of me, using #atPath: and #atPath:put: The first is special because it returns nil as soon as a key is missing. The second is special because it creates extra levels (instances of me) as needed to follow the path of keys. NeoJSONObject new atPath: #(one two three) put: 42; yourself. NeoJSONObject new atPath: #(one two three) put: 42; atPath: #(one two three). For the examples given above, the actual JSON looks like this: {"one":{"two":{"three":42}}} Sven
Hope this helps
Peter Kenny
From: Pharo-users [mailto:pharo-users-bounces@lists.pharo.org] On Behalf Of Markus Böhm Sent: 24 April 2017 18:42 To: pharo-users@lists.pharo.org Subject: [Pharo-users] Hot to retrieve values from Nested Dictionaries
May I ask: What's the idiomatic way to retrieve values from nested dictionaries?
(((dict1 at: 'key1') at: 'key2') at: 'key3')
Are all the brackets really necessary?
BR Mike
participants (10)
-
Cyril Ferlicot D. -
Esteban A. Maringolo -
Juraj Kubelka -
Markus Böhm -
Paul DeBruicker -
PBKResearch -
Peter Uhnak -
Ramon Leon -
Sven Van Caekenberghe -
Udo Schneider