Is there a way to remove duplicate (key-value) pairs from NSDictionary ?
EDIT:
My description was misleading, I have duplicate pairs e.g.
key1-value1
key1-value1
key2-value2
key1-value1
etc..
reversing key-value is not good idea because not all values can be keys.
You can do it with:
// dict is original dictionary, newDict new dictionary withot duplicates.
NSMutableDictionary * newDict = [NSMutableDictionary dictionaryWithCapacity:[dict count]];
for(id item in [dict allValues]){
NSArray * keys = [dict allKeysForObject:item];
[newDict setObject:item forKey:[keys objectAtIndex:0]];
}
yuo can also use lastObject instead of objectAtIndex:0 to leave other key for dup objects
One way is to put the key/value pairs into a dictionary by value/key and then converting that back to key/value.
I can't think of a built-in method.
If you iterate over the values, allKeysForObject: will give you an array of keys for each value and if you have more more than one key, that value has duplicates.
Related
Confusing !!!
I have one NSMutableDictionary called tempDict, having keys Freight, Fuel , Discount (and many more) with relevant values.
I am generating two different NSMutableArrays called arrTVBuyCharge and arrTVBuyCost from tempDict using this Code :
[arrTVBuyCharge addObjectsFromArray:[(NSArray *)[tempDict allKeys]]];
[arrTVBuyCost addObjectsFromArray:[(NSArray *)[tempDict allValues]]];
Problem : I want Freight, Fuel and Discount at the Top in the above arrays in same order (Ofcourse , with Ordering of Values).
What is the Optimum way to achieve this ?
It seems tricky at first, but it's simple when you think about it. All you want to do is get a sorted list of keys, and look up the value for each key as you add them to your arrays.
To get an array with the list of sorted keys:
NSArray *sortedKeys = [[tempDict allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
Then iterate through those and add them to NSMutableArrays:
NSMutableArray *arrTVBuyCharge = [[NSMutableArray alloc] init];
NSMutableArray *arrTVBuyCost = [[NSMutableArray alloc] init];
for (NSString *key in sortedKeys) {
[arrTVBuyCharge addObject:key];
[arrTVBuyCost addObject:[tempDict objectForKey:key]];
}
For even better performance, use the initWithCapacity method for the NSMutableArrays since you know the size.
This is the standard way of doing it.
1) Get three objects separately :
NSArray *mainKeys = #[#"Freight", #"Fuel", #"Discount"];
NSArray *mainValues = #[[tempDict valueForKey:#"Freight"],
[tempDict valueForKey:#"Fuel"],
[tempDict valueForKey:#"Discount"]
];
[arrTVBuyCharge addObjectsFromArray:mainKeys];
[arrTVBuyCost addObjectsFromArray:mainValues];
2) Remove them from tempDict :
[tempDict removeObjectsForKeys:mainKeys];
3) Add the objects from Updated tempDict :
[arrTVBuyCharge addObjectsFromArray:(NSArray *)[tempDict allKeys]];
[arrTVBuyCost addObjectsFromArray:(NSArray *)[tempDict allValues]];
This will make Freight, Fuel and Discount to be at index 0, 1 and 2 in your new Arrays.
Man, NSMutableDictionary always returns keys in a disordered fashion, if you really want to maintain order then you can sort it in alphabetical order or you can add 01, 02 ,03 serial numbers before your values to sort them in the order they were put it, later trim the first two characters of the string and use it.
this is my snippet
NSArray * alphabets = [NSArray arrayWithObjects:#"a",#"b",#"c",#"d",#"e",#"f",#"g",#"h",#"i",#"j",#"k",#"l",#"m",#"n",#"o",#"p",#"q",#"r",#"s",#"t",#"u",#"v",#"w",#"x",#"y",#"z",nil];
NSMutableDictionary * alphaToNum = [NSMutableDictionary dictionary];
NSInteger index =0;
for (NSString * character in alphabets) {
index++;
[alphaToNum setObject:character forKey:[NSNumber numberWithInteger:index]];
}
NSLog(#"%#",[alphaToNum objectForKey:#"d"]);
and every time I try to get some value for my key I only get 0 .
You need...
NSLog(#"%#",[alphaToNum objectForKey:[NSNumber numberWithInteger:[alphabets indexOfObject:#"d"]]]);
Your keys are NSNumbers, your objects are the letters from a to z. There is no object for key #"d". There will be an object, the string #"d", for the key [NSNumber numberWithInt:4]. Have you got your keys and objects the wrong way around? What do you actually want to do?
Following code will produce your desired result.
NSLog(#"%#",[alphaToNum objectForKey:[NSNumber numberWithInteger:4]]);
Problem with your NSlog is this.
Keys are made up of NSNumbers, which are starting from 1, not of alphabets. => since there is no key with letter 'd', it will send you null in return.
I'm sure this is a very obvious question but I'm not getting anywhere with it and I've been trying for half an hour or so now.
I have an NSMutableDictionary which has keys & values, obviously. Each key stores an array of objects. What I need to do is find a specific array in a key and get the list of the array. The catch is that I don't know the value of the key, I just know it's index. (EG: I know I need to find the array in the 2nd key).
I am almost certain this is a very easy & trivial thing to do but it's escaping me, I've only been doing Obj-C for a short while so not entirely at home with it yet!
Thanks,
Jack.
Use allKeys: to access the keys of your dictionary.
- (NSArray *)allKeys
Use as below .
NSArray* dictAllKeys = [dict allKeys];
if([dictAllKeys count] > 2)
{
NSArray* myArrayInDict = [dict objectForKey:[dictAllKeys objectAtIndex:1]];
// get the length of array in dict at 2nd key
int length = [myArrayInDict count];
}
The order will probably change if another key/value pair is added, it is a NSMutableDictionary. It is best not to rely on the order of a NSDictionary or NSSet.
Suggestion: Either use another container that does provide ordering such as NSMutableArray or find the item using the dictionary's value arrays, perhaps with NSPredicate.
I have an NSDictionary. It has keys and objects.
For the purposes of simplicity the keys are Question numbers and the objects are calculated Answer scores.
Now how I did it before was that I set the answer score as the keys and the question numbers as the objects. This way I could get an array of allKeys from the dictionary, sort it and then do something similar to:
for(NSString *string in tempArray){
NSLog(#"%#",[dictionary objectForKey:string]);
}
The (stupid - on my part) problem that I have now encountered however is that (obviously... duuhhh) the keys need to unique, and therefore when the calculated answer scores are the same, only one answer gets output!
I need a solution to this. In PHP you can multisort arrays. I was wondering if there was some similar solution in objective-c or indeed if someone had a better answer?
Any help here would be much appreciated.
Thank you.
Do you know about the allKeys, allValues and allKeysForObject method of the NSDictionary do you ?
One solution is to store the answer scores using an array of dictionaries containing only two key-value pairs. One key is the question number (or however your questions are tagged, i.e. “Q1.1”), while the other key is the actual answer score. For example:
static NSString * const QuestionKey = #"questionNumber";
static NSString * const AnswerScoreKey = #"answerScore";
NSMutableArray *allAnswers = [NSMutableArray array];
for (int i = 0; i < 20; i++)
{
// fill allAnswers array with random data
NSDictionary *answer = [NSDictionary dictionaryWithObjectsForKeys:
[NSString stringWithFormat:#"Q%d", i], QuestionKey,
[NSNumber numberWithInt:rand()], AnswerScoreKey,
nil];
[allAnswers addObject:answer];
}
// sort the allAnswers array based on score, highest first
NSSortDescriptor *sortDesc = [NSSortDescriptor sortDescriptorWithKey:AnswerScoreKey ascending:NO];
[allAnswers sortUsingDescriptors:[NSArray arrayWithObject:sortDesc]];
for (NSDictionary *answer in allAnswers)
{
NSLog(#"Question: %#, AnswerScore: %#", [answer objectForKey:QuestionKey], [answer objectForKey:AnswerScoreKey];
}
Disclaimer:
Untested and uncompiled code. Theory only.
I am not sure what you are actually trying to achieve. Do you want to sort an array of dictionary objects based on the value of the dictionary? If that is what you want, you can define your own comparator function and can define any custom sorting behavior. Please check sortedArrayUsingSelector: method of NSArray.
Edit : I am away from Mac currently but this previous question has a number of example code that can solve your problem. Rather than using object, you can use NSDictionary, though personally I would like to use another Question object instead of dictionary in this case. This question class will contain two value, id and score and then you need to sort the array of questions based on score just like the persons are sorted based on birthday.
I have an array of strings that are comma separated such as:
Steve Jobs,12,CA
Fake Name,21,CA
Test Name,22,CA
Bill Gates,44,WA
Bill Nye,21,OR
I have those values in an NSScanner object so that I can loop through the values and get each comma seperated value using objectAtIndex.
So, what I would like to do, is group the array items into new arrays, based on a value, in this case, State. So, from those, I need to loop through, checking which state they are in, and push those into a new array, one array per state.
CA Array:
Steve Jobs,12,CA
Fake Name,21,CA
Test Name,22,CA
WA Array:
Bill Gates,44,WA
OR Array:
Bill Nye,21,OR
So in the end, I would have 3 new arrays, one for each state. Also, if there were additional states used in the first array, those should have new arrays created also.
Any help would be appreciated!
You can use a NSMutableDictionary of NSMutableArrays - if the state encountered isn't yet in the dictionary, add a new array.
NSMutableArray* arr = [states objectForKey:state];
if (arr == nil) {
arr = [NSMutableArray array];
[states setObject:arr forKey:state];
}
Then you can insert values into the array, preferably as objects though as Dave DeLong mentions.
You shouldn't be maintaining this data as CSV. That's asking for a world of hurt if you ever need to manipulate this data programmatically (such as what you're trying to do).
You can naïvely break this data up into an array using NSArray * portions = [line componentsSeparatedByString:#","];. Then create a custom object to store each portion (for an example, see this post), and then you can manipulate those objects almost effortlessly.
Naively: (assuming array of strings called strings)
NSMutableDictionary *states = [NSMutableDictionary dictionary];
for (NSString *string in strings) {
NSString *state = [[string componentsSeparatedByString:#", "] lastObject];
NSMutableArray *values = [states objectForKey:state];
if (values == nil) {
values = [NSMutableArray array];
[states setObject:value forKey:state];
}
[values addObject:string];
}
Number of things about this -- first of all, I'm not at my computer, so there is a high chance of typos and or things that I missed. Second, you probably want to adapt the components separated by string line to handle whitespace better.