Hot to retrieve values from Nested Dictionaries

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

Hot to retrieve values from Nested Dictionaries

Markus Böhm-2
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
Reply | Threaded
Open this post in threaded view
|

Re: Hot to retrieve values from Nested Dictionaries

Juraj Kubelka

> On Apr 24, 2017, at 14:42, Markus Böhm <[hidden email]> 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


Reply | Threaded
Open this post in threaded view
|

Re: Hot to retrieve values from Nested Dictionaries

CyrilFerlicot
In reply to this post by Markus Böhm-2
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


signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Hot to retrieve values from Nested Dictionaries

Markus Böhm-2
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. <[hidden email]> 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


Reply | Threaded
Open this post in threaded view
|

Re: Hot to retrieve values from Nested Dictionaries

Esteban A. Maringolo
In reply to this post by Juraj Kubelka
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 <[hidden email]>:

>
>> On Apr 24, 2017, at 14:42, Markus Böhm <[hidden email]> 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
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Hot to retrieve values from Nested Dictionaries

Peter Uhnak
In reply to this post by Juraj Kubelka
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 <[hidden email]> 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
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Hot to retrieve values from Nested Dictionaries

Udo Schneider
In reply to this post by Markus Böhm-2
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.
> <[hidden email]
> <mailto:[hidden email]>> 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
>
>



Reply | Threaded
Open this post in threaded view
|

Re: Hot to retrieve values from Nested Dictionaries

Ramon Leon-5
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

Reply | Threaded
Open this post in threaded view
|

Re: Hot to retrieve values from Nested Dictionaries

Esteban A. Maringolo
2017-04-24 16:10 GMT-03:00 Ramon Leon <[hidden email]>:
> 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

Reply | Threaded
Open this post in threaded view
|

Re: Hot to retrieve values from Nested Dictionaries

Markus Böhm-2
In reply to this post by Udo Schneider

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" <[hidden email]>:
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. <[hidden email] <mailto:[hidden email]>> 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





Reply | Threaded
Open this post in threaded view
|

Re: Hot to retrieve values from Nested Dictionaries

Esteban A. Maringolo
2017-04-25 8:49 GMT-03:00 Markus Böhm <[hidden email]>:
> 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

Reply | Threaded
Open this post in threaded view
|

Re: Hot to retrieve values from Nested Dictionaries

Paul DeBruicker
JsonObject  has the doesNotUnderstand: trick too.




Esteban A. Maringolo wrote
2017-04-25 8:49 GMT-03:00 Markus Böhm <[hidden email]>:
> 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
Reply | Threaded
Open this post in threaded view
|

Re: Hot to retrieve values from Nested Dictionaries

Peter Kenny
In reply to this post by Markus Böhm-2

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:[hidden email]] On Behalf Of Markus Böhm
Sent: 24 April 2017 18:42
To: [hidden email]
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

Reply | Threaded
Open this post in threaded view
|

Re: Hot to retrieve values from Nested Dictionaries

Sven Van Caekenberghe-2
> On 26 Apr 2017, at 01:01, PBKResearch <[hidden email]> 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:[hidden email]] On Behalf Of Markus Böhm
> Sent: 24 April 2017 18:42
> To: [hidden email]
> 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