Совместное появление элементов в коллекциях
У меня есть массив массивов строк, таких как
#(#('smalltalk' 'pharo' 'cool')
#('smalltalk' 'pharo' 'new')
#('smalltalk' 'cool'))
И хочу подсчитать совпадения строк в разных коллекциях, поэтому я бы получил следующую информацию:
Smalltalk, pharo, 2
smalltalk, cool, 2
smalltalk, new, 1
pharo, cool, 1
pharo, new, 1
cool, new, 0 (0 случаев необязательны)
Каково было бы наиболее идиоматическое использование методов сбора Smalltalk (Pharo) для сбора этого данные? (Результат может храниться в некотором простом объекте с переменными element1, element2 и count.)
Я могу придумать какое-нибудь простое решение, но, как и в случае с аналогичными проблемами в прошлом, я обнаруживаю, что упускаю красивое решение Smalltalk и вместо этого делаю несколько глупых циклов.
2 ответа:
Я не вижу ничего идиоматического, это относительно сложная операция, я бы разложил на эти операции (код прототипа):
countAssociatedPairsIn aCollection | set pairs | set := aCollection flattenAllElementsInto: Set new. pairs := set generateAllPairs. ^pairs collect: [:pair | pair -> (aCollection count: [:associations | associations includesAll: pair])]
Если вы хотите сортировать по количеству, то это просто еще один sortedBy: # value
Если вы просто печатаете, но не собираете:, вы можете превратить некоторые петли в do:
Остается реализовать flattenAllElementsInto: (легко, что-то вроде сплющенного актива), и generateAllPairs (или какой-то allPairsDo: если вы просто печатаете, есть SequenceableCollection>> # комбинации: atATimeDo: что достаточно удобно для этой задачи).
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]
Это дает также обратные случаи, но я с этим согласен.
Он выглядит очень разборчивым для меня, теперь вопрос в том, эффективен ли он:|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.