Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get key with largest value from a dictionary in Smalltalk

I am using a Dictionary where the keys are strings and the values are integers. How can I get the key with the largest value out of this Dictionary?

I know there is the associationsDo: method I can use to iterate over both keys and values, but I don't know how to get the maximum value.

| countDict |
countDict := Dictionary new.
...
countDict associationsDo: [ :k :v | ??? ]
like image 318
JNevens Avatar asked Dec 15 '22 02:12

JNevens


2 Answers

Here is a way to do it following your idea:

| max largest |
max := nil.
countDict associationsDo: [:k :v |
  (max isNil or: [v > largest])
    ifTrue: [
      max := k.
      largest := v]].
^max

Here is another way, shorter but not very efficient:

 countDict isEmpty ifTrue: [^nil].
 ^countDict keyAtValue: countDict max

Also, if you have a countDict I suspect that it represents the number of occurrences of every key. If that is the case you shouldn't be using a Dictionary but a Bag. Instances of Bag represent collections of objects which may have several occurrences each. Examples:

names := Bag new.
people do: [:person | names add: person firstName].

and you may end up with

2 occurrences of 'John'
1 occurrence of 'Paul'
4 occurrences of 'Ringo'
7 occurrences of 'George'

names occurrencesOf: 'John'  ---->  2

The Bag will internally have a countDict sort of Dictionary, but to your model a Bag could reveal better your intention than a Dictionary because you will only need to add: elements without having to count them; the Bag will do it for you.

With a Bag your computation becomes

bag occurrencesOf: bag asSet max

The reason to send asSet is to avoid iterating several times on every value, which would happen if we simply put bag max. This simpler code will also work, but given that max iterates using do: and Bag implements do: by repeating the evaluation of the block for every occurrence of the element, this solution would be less efficient.

A better approach would be to re-implement max (and min) in Bag so that each element is iterated once. This would be similar to the code that we have above which followed your initial idea (associationsDo: [...). But let's leave the details of this as an exercise for the reader.

Anyway, if we re-implemnted max in Bag, the code would become simple and efficient at once:

 bag occurrencesOf: bag max
like image 52
Leandro Caniglia Avatar answered Mar 23 '23 23:03

Leandro Caniglia


Another nice way to do this:

(countDict associations detectMax: #value) key
like image 21
Uko Avatar answered Mar 23 '23 21:03

Uko