The idea is to return a "map" of the original series from original values to some derived value. For example, maybe we have a series of Strings, and I want to create a map from those Strings to their md5sum values.
I can code this as
Dictionary withAll: (setOfStrings collect: [:each | each -> (Security.MD5 new hash: 'Hello World')])
but I really would rather capture this as a common method. What would you call it?
setOfStrings asMapWithTransformedValues: [:each | ....]
ReplyDelete?
setOfStrings asDictionaryValuedBy: [:each | Security.MD5 new hash: 'Hello World']
ReplyDeletesetOfStrings associationsCollect: [:each | each -> (Security.MD5 new hash: 'Hello World')]
md5ify:
ReplyDeleteshould be similiar to collect:/reject:/select:
ReplyDeletee.g.
setOfStrings associate: [: each | Security.MD5 new
hash: each]
setOfStrings map: [: each | Security.MD5 new hash: each]
I think the method name needs to reveal the dictionary nature of the answer, and the fact that this is a conversion method from one kind of collection to another. By analogy with asSortedCollection:, we maybe don't need to specify what the block does.
ReplyDeletesetOfStrings asDictionary: [:key | Security.MD5 new hash: key]
I implemented this in Ruby once upon a time, and at the time called it "catalog". FWIW.
ReplyDeleteIt'd be fun if you could make it rhyme w/ select/collect/etc out of respect for Dan Ingalls and Arlo Guthrie. Candidates might include
#connect: (establishing connection between original and transformed object)
#transect: (representing a linear "slice" through the objects)
#inflect: (metaphor from language, where words are transformed according to their role)
#confect: (cookin' up something tasty)
I agree with camperov, associate: is a good name, if you want to key by the elements.
ReplyDeleteReads to me like
aCollection associate each with *some value*
catalog: in my mind goes the other way around (The elements are the values), i.e my internal reading would be
aCollection catalog each by *some value*
I like Steven's asDictionary: best.
ReplyDeleteThought about suggesting cache: but that's not obvious enough (though it describes a likely common use case).
How about
ReplyDeletesetOfStrings mapTo: [:each | Security.MD5 new hash: 'Hello World'].
or
setOfStrings mapEachTo: [:each | Security.MD5 new hash: 'Hello World'].
OTOH, I like map: and associate:, which read well and fit nicely with select: et al.
I don't like asDictionary:. This doesn't fit my thinking about conversion (I agree with Kent Beck on this one).
#project: and #project:into: are implemented for this feature in Slate.
ReplyDeleteAnother tactic is to go APL on it. I don't know the class library for your Smalltalk dialect, but many of them already have a general-purpose zipWith: method. This method takes two sequences and produces a sequence of pairs.
ReplyDeleteUsing such a method, you can write your example like this, without needing a new method:
Dictionary withAll:
(setOfStrings zipWith:
(setOfStrings collect: [ :each |
Security.MD new hash: 'Hello World' ]))
Lex, I don't see what that buys me over the original snippet. Dictionary withAll: takes a collection of associations. But there's also methods like withKeysAndValues: for creating dictioanries which takes pairs. But that's awfully roundabout, to me. Essentially, in this context, the -> method is an element based "zip" which zips two things together.
ReplyDeleteImplementation(body) of project: for reference, to clarify that it doesn't create Associations if the resulting dictionary doesn't use them:
ReplyDeletekeys@(Collection traits) project: valueBlock into: map@(Mapping traits)
[
keys do: [| :key | map at: key put: (valueBlock applyWith: key)].
map
].
arose := thyStrings perplect:
ReplyDelete[:key|
MD5 hash: key
].
"
An' I said: I can understand you takin' my <img>, so's I won't have any cached.exe
to 'pend in my cell.jpg there, but what'dya want my <dl> for?
An' the serif said:
We don't want no hangin'ins.
'N I said: Did ja think I'd wanna go hangin'ins myself -- for letterin'?
Well, the serif said he was makin' sure,
an' friends, he was, 'cuz he took out my <title> so's I couldn' <html> myself over the <head> and drown, he took my <tt><pre>s,
so I couldn't bend the columns, <>br>eak the <cr>roll the comment out the <br>eak the window and have an 16r1B.
"
Collection>>perplect: a1block
^self
inject: Dictionary new
into: [:map :each|
map += (each perplect: a1block)
]
Object>>perplect: a1block
^self isCollection
ifTrue: [self subclassResponsibility]
ifFalse: [self -> (a1block value: self)]
>>+= another
^self addAnsweringReceiver: another
Cross-posted from the VisualWorks forum on forum.world.st
ReplyDeleteIt seems the behavior Travis wants is "From a Collection, create a mapping where the key is the original object and the value is transformed from the key". Most replies seem to assume that the original input is a Set or able to become one without loss, though if not you could make it work producing an Array of Associations. I like the previously mentioned "project:" method name. Thus:
'abcabc' project: [ :e | e isVowel ]
which would produce an Array (preserving order and duplicates) of Associations.
You could write one implementation on Collection with the above behavior, and a refinement on Set to produce a Dictionary:
'abcabc' asSet project: [ :e | e isVowel ]
What do you think?
Just came up with a one method implementation:
ReplyDeleteconnect: aOneArgBlock
^self
inject: Dictionary new
into: [ :accumulator :e | accumulator at: e put: (oneArgBlock value: e); yourself]
( I posted this on the mailing list vwnc@cs.uiuc.edu, as seen at http://forum.world.st/Looking-for-a-good-method-name-td3056676.html#a3066226. Just thought I would add it to the comments here in case someone did not see the mailing list )