There is one question that I often ask myself while designing a program, and I am never quite sure how to answer it.
Let's say I have an object with multiple fields, amongst which there is one serving as the identifier to that specific object. Let's also say that I need to keep track of a List of such objects somewhere else.
I now have three, and probably even more, options on how to go about it:
Have my object contain its own identifier, and all its other fields. I now use a simple array (or whatever simple list collection) of my objects where I need it. When I am looking for one specific object, I loop through my list and check for identifier equality.
Pros: 1. "Clarity" for each object instance. 2.?
Cons: Manipulating a collection of these objects gets annoying
Have my object contain all fields beside its identifier. I now use a Map with identifier as key, and object as value. When looking for one specific object, I just lookup the identifier in the map.
Pros: easy lookups and insertions,?
Cons: object instance itself doesnt know what it is,?
Combination of both: use a map with identifier as key and object having its own identifier as a field as value.
Pros: mentioned above.
Cons: looks redundant to me.
What situations would call for what? Let's use the standard hello-world example of networking for example, a chat server: how would I handle multiple "groups/channels" people are in?
What about other applications?
Your question is very wide and, actually, contains two questions.
First is “Which data structure is better — dictionary or list?”. The answer is: it depends on performance you want to achieve on insertion and search operations. Basically if you need to look through the collection, then list is ok, and if you need to have fast look-up, then dictionary is better. Dictionary has more memory overhead than list.
The second is “Do I need to have an Id field inside an entity or can I use built in hash code?”. The answer is: it depends on how you will use your object. If you want Id just to store it in a dictionary, then, most likely, you can go with hash code. There is nothing wrong with storing Id of an entity inside that entity. Either you use Id or hash code, you need to be sure that this entity will be uniquely identified by id or hash. That's the main concern with it.
You can override GetHashCode method and make it return Id of your entity. Sometimes you can find such implementation when hash code is required for collection and Id is required for database.
So, it really doesn't matter what you will choose in the end if both approaches are working for you right now.
A map<Identifier, Object> will offer you O(1) performance when retrieving an object based on its identifier. There certainly are situations where you want to achieve that.
However, in other cases it might be redundant to use this approach. It all depends on the situation at hand.
Two guidelines may answer this question:
A use case that calls for a lookup where there is an expectation of a 1:1 relationship between the key and value implies a Map structure.
OOP implies that a key which is so closely related to an object as to preform a lookup should be encapsulated within that object.
Regarding the question of redundancy, consider the key in a map is nothing but an index. Indexes are as common in data as in books.
I haven't checked many dialects yet (in Pharo Association is a subclass of LookupKey, which is a subclass of Magnitude) but I presume this is fairly common.
Isn't this definition counterintuitive? Associations usually take part in unordered collections and I don't think a Smalltalker ever takes into account that their keys could be sent #<=. What I would like to know is whether this is something we inherited from old implementations of Smalltalk and never bothered to challenge, or it is just me who am missing something. Bottomline: has anyone ever used this feature?
I don't think that Dictionary needs that; all it needs are = and hash.
However, you often want to get a list of associations and sort them later (eg. to show them in some sorted list). Then, it is nice to have an order defined already.
And the cost is only a "<" method in Association (or LookupKey, if that is the superclass), so it comes almost for free by inheriting from Magnitude instead of Object.
Two related questions:
When you use [NSSet setWithArray:], does it remove duplicate object for you automatically?
How can you tell NSSet exactly what you want "duplicate" to mean? I.e. if you have a bunch of "College course" objects, each with a name and section number, and you wanted to transfer to an NSSet, keeping only one of each college course for a given name (for example, if you had three sections of Calculus, how would you tell it to only keep one section of calculus, even if their section numbers are different, so they're not perceived as identical by default).
Thanks! Let me know if that question was unclear at all. I was having trouble figuring out a way to word it.
Edit: This question is specific to NSManagedObjects, whose isEqual: method cannot be overridden.
From the documentation:
If the same object appears more than once in array, it is added
only once to the returned set.
Equality is determined here as throughout Cocoa with the -isEqual: method (and the -hash method). If you want two custom objects to be considered equal, you should override these appropriately, and you must override both. These are generally used so that objects that really are equivalent and generally interchangeable (but are separate objects) can be seen as such. In your example, it sounds like the college course objects really are "different" (ie, they represent different classes, even if they might share the same overall "calculus" topic), so it seems problematic to call those object instances "equal" if this is a large scale project/code base. In your case, you might consider adding the object to the set one by one and do your own comparisons as you add to make sure you get one of each "topic".
Since you can not access element of the NSMutableSet randomly, does this mean it is implemented like a linked list?
I.e. will it have faster insertion / deletion than a NSMutableArray?
The source code is available, so you can have a look: CFSet.c . (This is a Core Foundation counterpart to NSSet, but they are basically the same.) It's a hash table.
But you should also bear in mind that NSArray is, in fact, not implemented as an array. You can see the implementation here: CFArray.c. Maybe this blog article is easier to understand, although it's a bit dated (~5 years.)
No. Lookup time will be faster because it will use hashes.
I am no Objective-C progammer, but usually sets are implemented through hash-tables, which (if properly done) will yield O(1) for insert, delete and lookup.
Technically, hashes typically give you O(M), where M is the size of the key, but for a set you would simply use the id of the key object, which is constant, so you're back to O(1).
Sets are normally implemented with balanced binary search trees (e.g. red-black trees, avl trees).
Note: Although my particular context is Objective-C, my question actually transcends programming language choice. Also, I tagged it as "subjective" since someone is bound to complain otherwise, but I personally think it's almost entirely objective. Also, I'm aware of this related SO question, but since this was a bigger issue, I thought it better to make this a separate question. Please don't criticize the question without reading and understanding it fully. Thanks!
Most of us are familiar with the dictionary abstract data type that stores key-value associations, whether we call it a map, dictionary, associative array, hash, etc. depending on our language of choice. A simple definition of a dictionary can be summarized by three properties:
Values are accessed by key (as opposed to by index, like an array).
Each key is associated with a value.
Each key must be unique.
Any other properties are arguably conveniences or specializations for a particular purpose. For example, some languages (especially scripting languages such as PHP and Python) blur the line between dictionaries and arrays and do provide ordering for dictionaries. As useful as this can be, such additions are not a fundamental characteristics of a dictionary. In a pure sense, the actual implementation details of a dictionary are irrelevant.
For my question, the most important observation is that the order in which keys are enumerated is not defined — a dictionary may provide keys in whatever order it finds most convenient, and it is up to the client to organize them as desired.
I've created custom dictionaries that impose specific key orderings, including natural sorted order (based on object comparisons) and insertion order. It's obvious to name the former some variant on SortedDictionary (which I've actually already implemented), but the latter is more problematic. I've seen LinkedHashMap and LinkedMap (Java), OrderedDictionary (.NET), OrderedDictionary (Flash), OrderedDict (Python), and OrderedDictionary (Objective-C). Some of these are more mature, some are more proof-of-concept.
LinkedHashMap is named according to implementation in the tradition of Java collections — "linked" because it uses a doubly-linked list to track insertion order, and "hash" because it subclasses HashMap. Besides the fact that user shouldn't need to worry about that, the class name doesn't really even indicate what it does. Using ordered seems like the consensus among existing code, but web searches on this topic also revealed understandable confusion between "ordered" and "sorted", and I feel the same. The .NET implementation even has a comment about the apparent misnomer, and suggests that it should be "IndexedDictionary" instead, owing to the fact that you can retrieve and insert objects at a specific point in the ordering.
I'm designing a framework and APIs and I want to name the class as intelligently as possible. From my standpoint, indexed would probably work (depending on how people interpret it, and based on the advertised functionality of the dictionary), ordered is imprecise and has too much potential for confusion, and linked "is right out" (apologies to Monty Python). ;-)
As a user, what name would make the most sense to you? Is there a particular name that says exactly what the class does? (I'm not averse to using slightly longer names like InsertionOrderDictionary if appropriate.)
Edit: Another strong possibility (discussed in my answer below) is IndexedDictionary. I don't really like "insertion order" because it doesn't make sense if you allow the user to insert keys at a specific index, reorder the keys, etc.
I vote OrderedDictionary, for the following reasons:
"Indexed" is never used in Cocoa classes, except in one instance. It always appears as a noun (NSIndexSet, NSIndexPath, objectAtIndex:, etc). There is only one instance when "Index" appears as a verb, which is on NSPropertyDescription's "indexed" property: isIndexed and setIndexed. NSPropertyDescription is roughly analogous to a table column in a database, where "indexing" refers to optimizing to speed up search times. It would therefore make sense that with NSPropertyDescription being part of the Core Data framework, that "isIndexed" and "setIndexed" would be equivalent to an index in a SQL database. Therefore, to call it "IndexedDictionary" would seem redundant, since indices in databases are created to speed up lookup time, but a dictionary already has O(1) lookup time. However, to call it "IndexDictionary" would also be a misnomer, since an "index" in Cocoa refers to position, not order. The two are semantically different.
I understand your concern over "OrderedDictionary", but the precedent has already been set in Cocoa. When users want to maintain a specific sequence, they use "ordered": -[NSApplication orderedDocuments], -[NSWindow orderedIndex], -[NSApplication orderedWindows], etc. So, John Pirie has mostly the right idea.
However, you don't want to make insertion into the dictionary a burden on your users. They'll want to create a dictionary once and then have it maintain an appropriate order. They won't even want to request objects in a specific order. Order specification should be done during initialization.
Therefore, I recommend making OrderedDictonary a class cluster, with private subclasses of InsertionOrderDictionary and NaturalOrderDictionary and CustomOrderDictionary. Then, the user simply creates an OrderedDictionary like so:
OrderedDictionary * dict = [[OrderedDictionary alloc] initWithOrder:kInsertionOrder];
//or kNaturalOrder, etc
For a CustomOrderDictionary, you could have them give you a comparison selector, or even (if they're running 10.6) a block. I think this would provide the most flexibility for future expansion while still maintain an appropriate name.
I vote for InsertionOrderDictionary. You nailed it.
Strong vote for OrderedDictionary.
The word "ordered" means exactly what you are advertising: that in iterating through a list of items, there is a defined order to selection of those items. "Indexed" is an implementation word -- it talks more to how the ordering is achieved. Index, linked list, tree... the user doesn't care; that aspect of the data structure should be hidden. "Ordered" is the exact word for the additional feature you are offering, regardless of how you get it done.
Further, it seems like the choice of ordering could be at the user's option. Any reason why you couldn't create methods on your datatype that allow the user to switch from, say, alphabetical ordering to insertion-time ordering? In the default case, a user would choose a particular ordering and stick with it, in which case implementation would be no less efficient than if you created specialized subclasses for each ordering method. And in some less-used cases, the developer might actually wish to use any of a number of different orderings for the same data, depending on app context. (I can think of specific projects I've worked on where I would have loved to have such a data structure available.)
Call it OrderedDictionary, because that's precisely what it is. (Frankly, I have more of a problem with the use of the word "Dictionary", because that word heavily implies ordering, where popular implementations of such don't provide it, but that's my pet peeve. You really should just be able to say "Dictionary" and know that the ordering is alphabetical -- because that's what a dictionary IS -- but that argument is too late for existing implementations in the popular languages.) And allow the user to access in what order he chooses.
Since posting this question, I'm starting to lean towards something like IndexedDictionary or IndexableDictionary. While it is useful to be able to maintain arbitrary key ordering, limiting that to insertion ordering only seems like a needless restriction. Plus, my class already supports indexOfKey: and keyAtIndex:, which are (purposefully) analagous to NSArray's indexOfObject: and objectAtIndex:. I'm strongly considering adding insertObject:forKey:atIndex: which matches up with NSMutableArray's insertObject:atIndex:.
Everyone knows that inserting in the middle of an array is inefficient, but that doesn't mean we shouldn't be allowed to on the rare occasions that it's truly useful. (Besides, the implementation could secretly use a doubly-linked list or any other suitable structure for tracking the ordering if needed...)
The big question: is "indexed" or "indexable" as vague or potentially confusing as "ordered"? Would people think of database indexes, or book indexes, etc.? Would it be detrimental if they assumed it was implemented with an array, or might that simplify user understanding of the functionality?
Edit: This name makes even more sense given the fact that I'm considering adding methods that work with an NSIndexSet in the future. (NSArray has -objectsAtIndexes: as well as methods for adding/removing observers for objects at given indexes.)
What about KeyedArray?
As you said in your last paragraph, I think that InsertionOrder(ed)Dict(ionary) is pretty unambiguous; I don't see how it could be interpreted in any way other than that the keys would be returned in the order they were inserted.
By decoupling the indexed order from the insertion order, doesn't this simply boil down to keeping an array and Dictionary in a single object? I guess my vote for this type of object is IndexedKeyDictionary
In C#:
public class IndexedKeyDictionary<TKey, TValue> {
List<TKey> _keys;
Dictionary<TKey, TValue> _dictionary;
...
public GetValueAtIndex(int index) {
return _dictionary[_keys[index]];
}
public Insert(TKey key, TValue val, int index) {
_dictionary.Add(key, val);
// do some array massaging (splice, etc.) to fit the new key
_keys[index] = key;
}
public SwapKeyIndexes(TKey k1, TKey k2) {
// swap the indexes of k1 and k2, assuming they exist in _keys
}
}
What would be really cool is indexed values...so we have a way to sort the values and get the new key order. Like if the values were graph coordinates, and we could read the keys (bin names) as we move up/down along the coordinate plane. What would you call that data structure? An IndexedValueDictionary?
At first glance I'm with the first reply -- InsertionOrderDictionary, though it's a bit ambiguous as to what "InsertionOrder" means at first glance.
What you're describing sounds to me almost exactly like a C++ STL map. From what I understand, a map is a dictionary that has additional rules, including ordering. The STL simply calls it "map", which I think is fairly apt. The trick with map is you can't really give the inheritance a nod without making it redundant -- i.e. "MapDictionary". That's just too redundant. "Map" is a bit too basic and leaves a lot of room for misinterpretation.
Though "CHMap" might not be a bad choice after looking at your documentation link.
Maybe "CHMappedDictionary"? =)
Best of luck.
Edit: Thanks for the clarification, you learn something new every day. =)
Is the only difference that allKeys returns keys in a specific order? If so, I would simply add allKeysSorted and allKeysOrderdByInsertion methods to the standard NSDictionary API.
What is the goal of this insertion order dictionary? What benefits does it give the programmer vs. an array?