1

My collection is a Set that contains a number of dictionaries. How can iterate over each dictionary in the Set to select a specific key.

a Set(a Dictionary('age'->'25' 'code'->2512) a Dictionary('age'->'40' 'code'->'1243') a Dictionary('age'->'35' 'code'->'7854'))
eMBee
  • 793
  • 6
  • 16
ludo
  • 543
  • 3
  • 14
  • You script is very suspicious. Why would you repeat the keys `'age'` and `'code'` in every `Dictionary` to begin with. Are you by any chance trying to create a Json file or something like that? – Leandro Caniglia Jan 24 '18 at 19:16
  • Why suspicious @LeandroCaniglia. I created this json as an example to the real one I am working with as it has more keys – ludo Jan 25 '18 at 10:09
  • Maybe *suspicious* is not the word. What I meant is that your code many not be representative enough of the problem you are trying to solve (serialize some Smalltalk objects using a json format) and I just wanted to confirm what the actual problem was. – Leandro Caniglia Jan 25 '18 at 12:16

2 Answers2

4
set := {
    { 'age'->'25'. 'code'->'2512' } asDictionary .
    { 'age'->'40'. 'code'->'1243' } asDictionary.
    { 'age'->'35'. 'code'->'7854' } asDictionary.
} asSet.

If you are interested in retrieving just a single item, then detect: is the way to go. It will return the first item matching the predicate (the block). Note that Set has no defined order, so if you have multiple items matching, it may return different ones at different time.

d := set detect: [ :each | (each at: 'code') = '1243' ].
d. "a Dictionary('age'->'40' 'code'->'1243' )"

If you want to retrieve multiple items that all match the predicate, then use select:

multi := set select: [ :each | (each at: 'age') asNumber >= 35 ].
multi. "a Set(a Dictionary('age'->'40' 'code'->'1243' ) a Dictionary('age'->'35' 'code'->'7854' ))"

Update from comment for commenting:

As Carlos already stated, collect: will do what you need. It applies the transformation block to every item in the collection and then returns a collection of results.

codes := set collect: [ :each | each at: 'code' ].

Works for any collection

#(2 3 4) collect: [ :each | each squared ] "#(4 9 16)"

For further I recommend going through the Collections chapter in Pharo By Example book https://ci.inria.fr/pharo-contribution/job/UpdatedPharoByExample/lastSuccessfulBuild/artifact/book-result/Collections/Collections.html

Peter Uhnak
  • 9,617
  • 5
  • 38
  • 51
  • Thank you @Peter . how can I do that if I wanted to store the value of each code rather than specifying the value in the block? – ludo Jan 24 '18 at 10:38
  • 2
    A set is a collection, and there is a whole category of methods for iterating collections.If you want to use Smalltalk, you should very quickly get familiarized with them. To get the values of each code, you could use codes := set collect: [ :each | each at: 'code'].. They have also combined messages like #select:thenCollect: – Carlos E. Ferro Jan 24 '18 at 13:12
  • @ludo not sure what you mean, can you elaborate please? – Peter Uhnak Jan 24 '18 at 13:58
  • @Peter I meant getting the value of each code like Carlos explained but using a loop – ludo Jan 25 '18 at 10:06
0
mySet do: [:each | each do: [ :i | i doStuff ]]

or use detect (I`m not sure if detect works like this, I never used it so far):

mySet do: [:i | i detect: [ :each| (each at: 'key') doStuff ]].

or use keysDo:

mySet do: [:each | each keysDo: [ :k | k doStuff ]]

Check out: http://pharo.gforge.inria.fr/PBE1/PBE1ch10.html

The Fool
  • 16,715
  • 5
  • 52
  • 86