Reputation: 5041
I have an Array of Arrays of Strings like
#(#('smalltalk' 'pharo' 'cool')
#('smalltalk' 'pharo' 'new')
#('smalltalk' 'cool'))
and want to count the co-occurrencies of Strings in the different collections, so I would get the following information:
smalltalk, pharo, 2
smalltalk, cool, 2
smalltalk, new, 1
pharo, cool, 1
pharo, new, 1
cool, new, 0 (0 occurences are optional)
What would be the most idiomatic use of Smalltalk's (Pharo's) collection methods to gather this data? (The result could be stored in some simple object with element1, element2 and count variables.)
I can come up with some simple solution, but as with similar problems in the past, I find, that I miss a beautiful Smalltalk solution and do some stupid loops instead.
Upvotes: 2
Views: 781
Reputation: 5041
This gives also the reverse occurences, but I am fine with it.
It looks very legible to me, now the question is, if it is efficient:
|source bagOfPairs|
source := #(#('smalltalk' 'pharo' 'cool')
#('smalltalk' 'pharo' 'new')
#('smalltalk' 'cool')).
bagOfPairs := Bag new.
source do: [ :each |
each allPairsDo: [:first :second |
(first = second) ifFalse: [bagOfPairs add: {first . second}]
].
].
bagOfPairs inspect.
Upvotes: 4
Reputation: 9412
I see nothing that idiomatic, this is a relatively complex operation, I would decompose into these operations (prototype code) :
countAssociatedPairsIn aCollection
| set pairs |
set := aCollection flattenAllElementsInto: Set new.
pairs := set generateAllPairs.
^pairs collect: [:pair | pair -> (aCollection count: [:associations | associations includesAll: pair])]
If you want to sort by count, then it's just another sortedBy: #value
If you just print but not collect:, you can turn some loops in do:
It remains to implement flattenAllElementsInto: (easy, something like flattened asSet), and generateAllPairs (or some kind of allPairsDo: if you just print, there is SequenceableCollection>>#combinations:atATimeDo: which is convenient enough for this task).
countAssociatedPairsIn aCollection
| items |
items:= aCollection flattened asSet asArray sorted.
items combinations: 2 atATimeDo: [:pair |
Transcript cr;
print: pair; nextPutAll: '->';
print: (aCollection count: [:associations | associations includesAll: pair]);
flush]
Upvotes: 3