Currently, I have the following set up in my app:
For example, I have a gamelist, where the games have different states and I would like a certain state to be in a certain section etc.
Since I have 3 different states I'll use a NSDictionary with State as key and Array as value and put a certain game with a certain state in the correct array.
Then my code for numberOfRowsInSection would be something like:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString* state = [self getStateForSection:section];
return [[obj objectForKey:state] count];
}
The problem is I dislike having the objects in arrays since then I have to look through the whole array whenever I want to access a certain match.
I would instead like to have all matches in a single NSDictionary with matchID as key and NSDictionary with as value (the match).
But how would I do in UITableView then?
I could do something where I return allKeys of my NSDictionary but I still have to iterate it to find their current state and add their key to the appropriate list?
You could just also build a NSDictionary from matchID to match on the side as well, simply reusing the same objects and keeping the NSDictionary of NSArrays just for the table data source. Then the problem is that you have to update both when the data changes. You may also want to look into NSArray filteredArrayUsingPredicate:
Another possibility is using another data structure known as the sorted dictionary which keeps its keys in a specific order. That way you can ask for all the values as an array for the table view and get a constant order, but still be able to do a lookup with a matchID directly to a match.
Related
Say I want to access all objects in some NSDictionary object.
I want to iterate like this:
for (key in dict){}
Is it guaranteed that for each run the objects in the dictionary will be accessed in the same order?
PS. Let me explain my question more thoroughly: if I iterate dictionary once and access keys in some concrete order - will I have the same order on second iteration attempt?
Sorting of keys is not guaranteed because of the nature a key is placed inside the NSDictionary. But that is only the half answer. read on...
If we iterate thru the dict with a for (NSString* key in dict) loop or even more unspecific with for (id<NSCopying> key in dict) loop then we use actually NSEnumeration. Those kind of iterations are unpredictable to you. NSEnumeration and NSFastEnumeration do not iterate the dict with indexes. They go thru by addresses or hashes of keys, so to speak. Thats also a blurry answer that is not complete.
Keys inside a dict are unique compared to other keys in the same dict.
Which is the great thing and why you would use a NSDictionary or NSMutableDictionary instead of indexed NSArray or NSPointerArray or unspecific NSSet, and specially offered datatypes as NSOrderedSet, NSOrderedCollection. NSMapTable and NSHashTable tend to behave like NSDictionaries but they have a completely different way how they store the keys and how they iterate.
So what happens when you rewrite a keyed value in NSDictionary?
NSDictionary *dict = #{
#"A" : #(1234),
#"B" : #(4321)
}
NSMutableDictionary *mutabledict = [dict mutablecopy];
mutabledict[#"A"] = #(5678); //beware this only works on NSMutableDictionary.
dict = mutabledict;
here we exchange the value of the first declared key A.
mutabledict[#"A"] [key] is a getter subscript used to find the address of the keys value pair. Nothing is changed on the key itself. So the order of keys stays as it was the moment the unique key was copied in.
You need to be careful when you create a mutablecopy, because then whole pairs are copied. The outcome in sorting may be unpredictable as well.
Simple: But Accessing keys value does not change their memory layout.
But: NSDictionary are immutable, so the keys can not be changed once they are set. So you can say:
The keys are ordered in the order they where stored the first time. But you can't access the values stored in a guaranteed order when you don't know the order the keys:value pairs where placed and with this process its unique keys copied into the dict.
If you can't control the order the keys are set then the keys order is unknown to you, (respecting the question) not undefined. And NSEnumeration iteration gives you not a real picture of the order they are stored.
How to deal with that?
The easies way to get known ordered sorting of keys is by manually sorting all its keys like..
NSArray *sortedKeys = [dict.allKeys sortedArrayUsingSelector:#selector(compare:)];
which is giving you ascending order of keys and lets you iterate thru your dict with arrays indexes containing addresses to keys. like ..
for (unsigned int i=0; i<sortedKeys.count; i++) {
NSString* key = sortedKeys[i];
dict[ key ] = yourValue;
}
if keys are not of interest but the guaranteed sorting is more important to you, then you could convert the NSDictionary into a sorted NSArray without keys and access its indexes in a loop. With the obvious back-draw to have no keys unless you store them manually.
id notfoundmarker = #"empty";
NSArray *sortedkeys= [dict.allKeys sortedArrayUsingSelector:#selector(compare:)];
NSArray *oneForOneSorted = [dict objectsForKeys:sortedkeys notFoundMarker:notfoundmarker];
for (unsigned int i=0; i<oneForOneSorted.count; i++) {
id<NSObject> value = oneForOneSorted[i];
NSLog(#"%#", value);
};
My question was different: if I iterate dictionary once and access keys in some concrete order - will I have the same order on second iteration attempt?
Short Answer
In all probability yes
Longer Answer
How a dictionary is constructed internally is not specified, and there are multiple ways to represent dictionaries, all that is known is that key values must be hashable which implies hashing is used somehow.
It is also not know what algorithm a dictionary uses to provide the keys when enumerating them, and again for an particular possible representation there could be more than one enumeration algorithm possible.
So we have a lot of unknowns.
What do we know?
In the absence of threading, random number generation, and anything similar an Objective-C program is deterministic, a trait it has in common with C, Swift, Java, C# and a host of other languages.
NSDictionary is not thread-safe so its unlikely to use threading in its implementation.
And why would it use random numbers?
NSDictionary is also an immutable type so once constructed there is no obvious reason to re-order its internal storage in response to calls querying its contents.
So, in all probability, you will get the same key order on every enumeration.
Without the source though you can't be certain, you cannot prove the absence of something by black-box testing. Maybe the programmer decided that every millionth enumeration they'd throw a little randomness in – just for fun ;-) Is this likely? Maybe not (its probably a good way to get fired!), but it's not impossible.
If you ask out of curiosity, then good stay curious!
If however you want to rely on the order being deterministic for code correctness then sort the keys (into a peculiar order if you wish as long as its deterministic), the cost of doing so will in all probability be inconsequential.
HTH
The docs state that for the allKeys property the order of the elements in the array is not defined.
So you can just sort the keys array to ensure it's always sorted.
Each iteration will be in a random order because Swift dictionaries don't prioritize order. Arrays do, however, so you can sort the dictionary (by key or value) to produce an array of tuples, which in effect can be treated like a sorted dictionary.
let dictionary = ["k4": 3, "k2": 8, "k1": 6]
let sortedArrayOfTuples = dictionary.sorted(by: { $0.key < $1.key })
for entry in dictionary {
print(entry.key)
}
for entry in sortedArrayOfTuples {
print(entry.key)
}
I've got a value like so: #"2329300" and I've got a NSDictionary like so :{#"John Appleseed":[#"2329300",#"2342322",#"32i249"]}
How do I find the index of the key/value pair in the NSDictionary when I've only got a string value of the entire list that's known as the value. I'm assuming there's no duplicates in the dict.
I know that there's indexForObject on a NSArray but is there a similar thing for a dict?
I imagine it would look something like this:
[NSDictionary indexForValue:value]; // returns index number.
And even then the NSString doesn't match the value, so I'd need a workaround for that too.
You have a basic misunderstanding. Dictionaries are unordered collections. They do not have any particular order for their key/value pairs. You can't have indexes to the key/value pairs because that implies a fixed order.
Think of a dictionary as a bunch of kids milling around on a playground. You can call out a kid's name "Johnny, come here!" and fetch that kid (use a key to find an object) but what does order mean for kids that won't sit still?
You can create an array of the keys from a dictionary and sort that into a particular order (an alphabetical list of the kids on the playground) if that's what you want, or you can create an array of dictionaries, or an array of a custom data object that contains any arbitrary properties that you want.
EDIT:
For a table view, an array of dictionaries is probably a good choice. Each entry in the array contains a dictionary with all the settings for a cell in the dictionary. If you have a sectioned table view then you want an outer array for sections, containing inner arrays for the rows, and each entry in the inner array containing a dictionary.
I tend to prefer custom data objects to dictionaries though. (An object that just has properties for each setting I want.) That way the list of values and their types is crystal-clear and fairly self-documenting.
I am going to store a list of values in a plist and retrieve them. The list will be searched for a value (which may change each time) each time the search method is called. There will probably be about 10 values in the list.
Is either NSArray or NSDictionary better for a search?
I think that NSArray is more appropriate because right now, at least, I don't have a key-value pair data set, just a list.
Could someone confirm and perhaps offer the best method for search the array?
Thanks
The problem is conceptual:
If you have a list of value, you mustn't use NSDictionary. The appropriate data structure is NSArray or NSSet.
Basically, NSSet is faster than NSArray, because doesn't have to consider the order etc.
So if you need just to search a value and the order doesn't matter, the best data structure to use is NSSet (or NSMutableSet if you need it mutable).
Dictionaries will be faster for searching than arrays because the keys are hashed. With an array the system has to check all the items until it finds a match.
The docs for NSSet say that sets are faster in testing for membership than arrays. If you don't have values to store for each key, the best option might be to store the data to your plist as an array. At runtime, read the array, and load it's contents into a set using the NSSet class method setWithArray:
If your data sets are large (many thousands of items) I would suggest doing performance testing with dictionaries where all the values are NSNull against an NSSet. (With a dictionary you'd use objectForKey: and with a set you'd use the containsObject: method
Ignoring timing the best option would be to use an NSArray. NSArray has all sorts of useful methods such as
(NSArray *)filteredArrayUsingPredicate:(NSPredicate *)predicate
and
(NSIndexSet *)indexesOfObjectsPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
that you can use for searching within an array.
This question already has answers here:
What's the difference between a dictionary and an array?
(6 answers)
Closed 10 years ago.
I'm in a dilemma in terms of which of the two I should use. I will be retrieving a group of data via a restful API (returns json) and I'm not sure how I should store them before I display it on my UI View Table.
eg.
{"Events":[{"Id":5,"Name":"Event 1 2013"},{"Id":6,"Name":"Event 2 2013"}]}
I've been reading tutorials and some would use NSMutableArrays while some would use NSMutableDictionary.
How should I go about it?
BTW: I'm displaying the data on UI View table that will redirect the user to another page when tapped and if they decide to go back will have to show the previous view without reloading (uses UinavigationController)
Thanks!
EDIT:
Also, just to give you an idea on what I'm trying to do. I'm trying to follow this tutorial on splitting the data I get into section headers. On this tutorial it's using NSDictionary.
http://www.icodeblog.com/2010/12/10/implementing-uitableview-sections-from-an-nsarray-of-nsdictionary-objects/
If I use NSArray, would that affect the performance?
In NSArray - every item in the collection has an integer index, so there is an explicit order to the items. When you're retrieving/replacing/removing the stored object from the NSARRY,you need to specify the corresponding object index of that stored object.
NSDictionary - derived from the word called entry. Each entry consists of one object that represents the key and a second object that is that key’s value. Within a dictionary, the keys are unique. That is, no two keys in a single dictionary are equal (as determined by isEqual:).When you're retrieving the object from the dictionary you need to specify the key value for the objectForKey
Whenever if you're parsing the plist then NSDictionary would be ideal.You can refer apple's document here for more explanation about NSDictionary.Happy coding :)
The lookup times on NSDictionaries are faster than on NSArrays. That's one of the main advantages. Here's a link to the Apple documentation.
Generally, if you need to access data in an indexed fashion (like you need to for rows in a table) then you should use an array because you can access any specific index using indexOfObject:
Now, if you have a lot of information for each row then you should have an array of either custom objects or an array of dictionaries.
Dictionary are always faster than Arrays. Dictionary maps keys to objects, just like a hash table. It's an associative array.
For searching some value you need to iterate for arrays, in dictionary you retrieve it by key.
If you want the collection to be in some sorted order or arrival order then Array is the proper type for you.
Dictionary lacks when you end up getting two same keys.
And I feel good to use arrays for tableViews as I can directly associate row to index.
I have a hierarchy like so -> Days (Table) -> Time (Table) -> Info (View).
Would it be better to store the information as a NSDictionary, with the Days as the keys and the Time as an NSArray for each key, or the Days as NSArray, with another NSArray for Time?
Key things to note:
I'd like the sort the days and Time.
I would be able to delete some Time data within the NSArray if I wanted to.
If you are going to delete or replace elements in an array you must use the mutable versions, NSMutableArray and NSMutableDictionary. I would probably use an array for this purpose.
I would use an NSMutableDictionary of days with an NSMutableArray of times for each day. That way you avoid trying to keep two separate arrays in sync since each "day" key will always point to your array of times.
You can sort your array of times any way you want since it's an array, and you can choose how to show your days in the table simply based on the key. You can access an array of all your keys using the [dictionary allKeys] method.
For example, in viewDidLoad you can use the [dictionary allKeys] method to get an array of the keys of your dictionary. You can sort this whichever way you like, and then iterate through the array in the cellForRowAtIndexPath tableview datasource method.
-(void)viewDidLoad {
/* keys = NSMutableArray instance variable
dictionary = the dictionary of days, with each days value being an array of times
*/
keys = [dictionary allKeys];
//sort however you want
}
And then in your didSelectRowAtIndexPath delegate method, you know which key they selected based on the indexPath.row of the selection and the row of your keys array.