Availability of bidictionary structure? - ios

I'm facing a case in my application where I need a bidirectional dictionary data structure, that means a kind of NSDictionary where your can retrieve a key with a value and a value with a key (all values and keys are unique).
Is there such a kind of data structure in C / ObjectiveC ?

You can do it with a NSDictionary:
allKeysForObject: Returns a new array containing the keys
corresponding to all occurrences of a given object in the dictionary.
(NSArray *)allKeysForObject:(id)anObject Parameters anObject The value to look for in the dictionary. Return Value A new array
containing the keys corresponding to all occurrences of anObject in
the dictionary. If no object matching anObject is found, returns an
empty array.
Discussion Each object in the dictionary is sent an isEqual: message
to determine if it’s equal to anObject.
And:
objectForKey: Returns the value associated with a given key.
(id)objectForKey:(id)aKey Parameters aKey The key for which to return the corresponding value. Return Value The value associated with
aKey, or nil if no value is associated with aKey.

Literally, the answer is No.
As a workaround you may create a helper class which manages two dictionaries.
Another approach is to create a thin wrapper around C++ container which implement this: boost's Bimap.
When using ARC and Objective-C objects as values or keys in C++ containers, they will handle NSObjects quite nicely. That is, they take care of memory management as you would expect - and you even get "exception safety" for free. Additionally, C++ standard containers are also a tad faster, use less memory, and provide more options to optimize (e.g. custom allocators).

Related

isEqualToArray or isEqualToDictionary how deep can it compare?

Ohkk So I have many scenarios here.
case:1
A NSArray of dictionaries with a key as type NSString and value also of type NSString.In this case if I change one value in the NSdictionary on the array and try comparing old array with new one it works. isEqualToArray returns false
case:2
A NSArray of dictionaries with a key type as NSString and value type of some model object with attributes like name,address,DOB . So if I change one value in the model object like name and insert in the dictionary with same key. And compare the arrays with old one still works. isEqualToArray returns false
Now this can go on .What if I have a NSArray in my model object which of again a primitive type of some model.What will happen?? Does isEqualToArray compares almost everything in the values of the objects like deep-serializing compare or it has to stop somewhere??
When you compare arrays, the NSArray isEqual: method first checks that both arrays have the same number of elements (otherwise, they are obviously not the same), and then it goes through all the elements one by one and compares them in turn using the isEqual: method. So if your array contains other arrays, or dictionaries, or other objects, then arrays are again compared as just described, dictionaries will be compared as I will describe, and other objects are compared by sending isEqual.
When you compare dictionaries, the NSDictionary isEqual: method first checks both dictionaries have the same number of key/value pairs. Then it takes the first key of the first dictionary, and that key must be present in the second dictionary, and the objects must be the same. Then the second key, the third key and so on.
It all works as long as each class involved has a proper implementation of the isEqual: method. It really has nothing to do with isEqualToArray:. All that does is call isEqual: on each object in the two arrays. So it depends on those objects having a valid isEqual: method (and hash method).
As long as your model object's isEqual: method properly compares each of its properties, you will get the expected result.

iOS Dictionary Response by added objects [duplicate]

I've run into the same problem as found in this question. However, I have a follow-up question. I seem to be in the same situation as the original asker: I have a plist with a hierarchy of dictionaries that define a configuration screen. These are not mutable and will stay the same throughout the application. Since the original discussion seems to focus on problems arising from mutating the dictionary, I must ask for comfirmation: is the order of a dictionary guaranteed the same as they are in the plist, i.e. as it is read (with initWithContentsOfFile)? Can I use allKeys on it in this case to get a correct-order array of keys if the dictionary never changes?
No, the keys are not likely to appear in the same order as your plist file. I can't look under the hood, but I would guess that the keys are ordered in whatever way that provides an efficient look-up. The documentation for allKeys says that the order of the elements in the array is not defined.
If you need an NSDictionary that maintains order, take a look at CHDataStructure's CHOrderedDictionary, which does exactly that. I use it all the time.
I would not assume that the keys will be in any kind of order because allKeys does not guarantee order.
Internally, NSDictionary uses a hash table.
From allKeys description:
The order of the elements in the array
is not defined.
If you want to display values in some order then get the keys, sort the keys array and then get the value for each key.
Nothing at all is guaranteed about order. It’s not even guaranteed that iterating over a dictionary twice will give you the keys in the same order.

What is the purpose of a DictionaryIndex in Swift?

Per the header documentation on Dictionary in Swift:
A hash-based mapping from Key to Value instances. Also a
collection of key-value pairs with no defined ordering.
Note in particular- no defined ordering.
With this in mind, I'm having trouble fully understanding these computed variables (and the related methods that take these types):
// The position of the first element in a non-empty dictionary.
var startIndex: DictionaryIndex<Key, Value> { get }
// The collection's "past the end" position.
var endIndex: DictionaryIndex<Key, Value> { get }
The "index" here is a DictionaryIndex.
However, the documentation on DictionaryIndex is kinda circular here:
Used to access the key-value pairs in an instance of
Dictionary<Key, Value>.
What actually is the purpose of DictionaryIndex?
We know that a Dictionary is composed of keys and values. Every key is mapped to a value based on some internal calculations. Here the mechanism used for this purpose is Hashing.
From wikipedia:
A hash table uses a hash function to compute an index into an array of buckets or slots, from which the correct value can be found.
Consider that a Dictionary is a Hash Table, which uses some hash function and returns an object of type DictionaryIndex - using which you can access particular object directly in the Dictionary.
Correct me if I am wrong!

Best way to represent un-ordered data in a plist

I'm making a plist to hold genre synonyms. The list of synonyms for a given genre doesn't have any inherent order to it.
Should I use an array (which implies an order that doesn't exist) or a dictionary (which implies there's a corresponding value for each key, which doesn't exist).
Simply put--to store an unordered set in a plist, how should I represent it and why?
(To clarify: If there were a Set data structure in the plist editor, I would use that, but I only have Array and Dictionary to choose from.)
More details: I'm going to be looking up by the primary representation of the genre, thus the outer data structure in the plist has to be a dictionary.
But then for the synonyms, the only operation necessary is to enumerate them using a block.
So either an array or a dictionary will do. However, I'm concerned that using an array will imply an order that doesn't have any semantic meaning. On the other hand, is it a common occurrence to have dictionaries in plists that don't have a corresponding value?
Editing again to respond to Josh's comments:
I like your idea of converting into an NSSet after reading in the plist. However, I could still do that with a dictionary, right? So not sure why an array is the obvious choice.
If someone else edits the plist, they might think there's a meaning to the order, when in reality, the ordering is arbitrary.
Surprised no-one has defended using a dictionary instead of an array. Is there a reason a dictionary shouldn't be used in a plist for this purpose?
If you don't care about order, then the arbitrary order you get from building an array is equivalent to the arbitrary order you'd get by using a set. You can also very easily convert an array in a plist to an NSSet after reading it back: +[NSSet setWithArray:]
So use an array.
I would just use an array, since you say there's no corresponding key for a dictionary entry.
At the same time, if you're typing in a large number of entries into plist files (www), your fingers may get tired from dealing with the raw XML or plist editor stuff. You might want to consider a different way to save your synonyms?
Use an NSArray if lookup by item is not needed. If lookup is needed use an NSDictionary.

What is the relationship between elements of plists, arrays and dictionaries?

I've got a simple program that needs to log and persistently store 2 simple pieces of data produced each time the user selects an item in a table view. The two pieces of data are 1) the time of the tap (NSDate) and 2) the name of the item tapped (NSString). At this point, this information is in this form:
TimerEvent *latestTappedEvent = [[TimerEvent alloc] init];
latestTappedEvent.timeTapped = NSDate.date;
latestTappedEvent.activityTapped = tappedItem.itemName;
The two data pieces must remain associated with each other.
My question is this:
How do I get this data into and out of a plist, ordered chronologically?
In my research, I have only become more confused. It's just not obvious to me how to use a plist. Initially, I thought I could use an NSMutableDictionary with latestTappedEvent.timeTapped as a key, and latestTappedEvent.activityTapped as the value. But when I tried to construct the plist manually, it appears not to be possible, wanting instead a string for a key.
If anyone can help me understand this, preferably by giving a graphic representation of the relationship among these different elements, I would be forever grateful.
Dictionaries and arrays both store 'things' - and the things stored are retrieved and set by using 'something else' to do a 'lookup' on the data structure. In an array, that lookup is the index in the array where an object is stored. In tabular form:
Index Storage
0 "some string stored at index 0"
1 "some other string"
2 <some other object, stored at index 2>
To find "some string stored at index 0" you would need to know it's stored at index 0 and ask the array for the object at that index. So arrays use integers to look up objects stored in them, and these integers must be in the range of 0 to the array's count minus 1. The use of integers to look up items in the array also gives the array order - the top-to-bottom ordering you see in the table above is the same order that iterating in code would yield.
Dictionaries use arbitrary objects to do the lookup which also means there's no ordering in a dictionary, there's just a set of associations of keys and what they refer to. In tabular form:
Key Storage
"name" "a string that will be accessed using the key 'name'"
"number" <some numeric object, that will be accessed using the key 'number'>
<object> "will be accessed with key <object> which is an arbitrary object"
To get "a string that will be accessed using the key 'name'" from this dictionary, you ask the dictionary for what's stored under the key "name".
In the above examples, I gave the table heading "Index - Storage" or "Key - Storage", but to circle back to the point that these structures both store things hat are accessed using another thing, let's view the array with a more generic table:
Thing used to access the thing that's stored Thing that's stored
0 "some string stored at index 0"
1 "some other string"
2 <some other object, stored at index 2>
And again, the dictionary, with the same table:
Thing used to access the thing that's stored Thing that's stored
"name" "a string that will be accessed using the key 'name'"
"number" <some numeric object, that will be accessed using the key 'number'>
<object> "will be accessed with key <object> which is an arbitrary object"
Also, let's view your class TimerEvent in the same table:
Thing used to access the thing that's stored Thing that's stored
timeTapped <date object>
activityTapped "name of an activity"
The items in the left column are Objective-C property names, and the items on the right are the values those properties contain. Now, take another look at the dictionary - the items on the left are arbitrary values (in practice they are commonly strings) and the items on the right are other arbitrary values. Hopefully you can see the connection here - that you can generally represent an object's properties as a dictionary that maps the string representation of a property name to the value the property stores. So, if you want to represent the TimerEvent object in a dictionary, you'd end up with a representation like:
Key Object
"timeTapped" <date object>
"activityTapped" "activity name"
The tables above illustrate the commonalities and differences between arrays, dictionaries, and other objects, and show that using a dictionary to map property names to property values can represent the properties of any given object. So, how would the code to do this look? Let's say we want to represent the TimerEvent object timerEvent in an NSDictionary:
NSDictionary *timerEventRepresentation = #{ #"timeTapped": timerEvent.timeTapped,
#"activityTapped": timerEvent.activityTapped};
And here's how we could create a TimerEvent from a dictionary representation:
TimerEvent *timerEvent = [[TimerEvent alloc] init];
timerEvent.timeTapped = timerEventDictionaryRepresentation[#"timeTapped"];
timerEvent.activityTapped = timerEventDictionaryRepresentation[#"activityTapped"];
The purpose behind coercing all your objects into dictionaries is that the property list format only serializes a few classes - NSArray, NSDictionary, NSString, NSDate, NSNumber, and NSData. So we write code to represent non-supported classes using the supported ones, and vice versa, to serialize these objects in plists.
As an addendum, you mention that you need to store a record of all taps, and sort them. As I mentioned above, arrays inherently order the things they store, so that is the appropriate solution here. You'd want to build something that looked like this:
Index Item
0 <dictionary representing first tap>
1 <dictionary representing second tap>
...
n <dictionary representing n-1th tap>
In code, serializing each tap would take the same form as was described earlier, but make sure to add an extra step of calling addObject: on an NSMutableArray property with the newly-created dictionary as the parameter.

Resources