Remove (not exact) duplicates of NSDictionaries from array - ios

I have an NSMutableArray of many NSDictionaries that contain keys like "Title". In some cases there are duplicates of dictionaries with the same "Title" but differences in the other keys.
How can I remove the dictionaries that have the same "Title" key and leave only one in the array?
Thanks

Sort the array using NSSortDescriptor on the key path 'title'. Next, loop over the array and build a new array:
NSString *lastTitle = nil;
NSMutableArray *result = [NSMutableArray array];
for (NSDictionary *d in array) {
NSString *testTitle = [d objectForKey:#"title"];
if (![testTitle isEqualToString:lastTitle]) {
[result addObject:d];
lastTitle = testTitle;
}
}
Now result contains your filtered list.
It's important to sort the array first for this algorithm to work.

Related

Objective-C: Remove duplicates efficiently from large data structures

I have an object containing an array of NSNumbers (indexes) and an array of NSDictionaries (indexesTitles) corresponding to indexes, containing some info.
I have to call a method for each object.index and associate object.indexTitles to the returning results, saving them into a single array.
At the end of it, I want to remove indexes duplicates, preserving the associated indextTitles in an efficient way, because I'm working with large arrays.
NSMutableArray *resultArray = [NSMutableArray array];
NSMutableArray *titlesArray = [NSMutableArray array];
for(NSNumber *index in object.indexes)
{
NSArray *resultsIndexArray = [self methodThatReturnsAnArray];
NSString *indexTitleDictionary = [object.indexesTitles objectAtIndex:i];
for(NSNumber *resultId in resultsIndexArray)
{
[titlesArray addObject:indexDictionary];
[resultArray addObject:resultId];
}
i++;
}
[fullResultsArray addObject:titlesArray];
[fullResultsArray addObject:resultArray];
I've found that the most efficient way to remove duplicates is using an
NSOrderedSet like this:
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:resultArray];
resultArray = [orderedSet.array mutableCopy];
How can I remove the corresponding entries in titlesArray? how can I preserve the association?
I've also tried to use a NSDictionary like {resultId, titleDictionary} and storing them into an array, but I haven't found a efficient way to remove dictionaries with the same result, they are all too slow.
Any suggestion?
It is not completely clear to me what your problem is, maybe this will help:
A good way to remove duplicates is not to add them in the first place, replace:
for(NSNumber *resultId in resultsIndexArray)
{
[titlesArray addObject:indexDictionary];
[resultArray addObject:resultId];
}
with:
for(NSNumber *resultId in resultsIndexArray)
{
// only add if resultId not already in resultArray
if( ![resultArray containsObject:resultId] )
{
[titlesArray addObject:indexDictionary];
[resultArray addObject:resultId];
}
}
The containsObject: call requires a linear search, if your data set is large you might wish to change resultArray to an NSMutableSet and titlesArray to an NSMutableDictionary mapping from resultId to indexDictionary values.
HTH

Remove duplicates from large NSMutableArray

I have a large mutable array with lots of duplicate values in alphabetical order.
I need to be able to convert my array *Array into a new array that contains one entry for each string variant.
I am currently using:
NSArray *array = [NSArray arrayWithObjects:papersObject.paperSubject, nil];
NSCountedSet *paperSet = [[NSCountedSet alloc] initWithArray:array];
NSMutableArray *namesArray = [[NSMutableArray alloc] initWithCapacity:[array count]];
[namesSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop){
if ([paperSet countForObject:obj] == 1) {
[namesArray addObject:obj];
}
}];
NSLog(#"%#", namesArray);
But this returns a long list of the same array, still with duplicates.
Any ideas?
What about:
NSArray *arrayWithNoDuplicates = [[NSSet setWithArray:papersObject.paperSubject] allObjects];
A. What is namesSet? paperSet?
B. However:
NSOrderedSet *set = [NSOrderedSet orderedSetWithArray:array];
NSArray *arrayWithUniquesIsAnOrderedSet = set.array;
BTW: I would highly recommend to use an ordered set instead of an array, because an array with unique objects is an ordered set.

How to populate an array with dictionaries containing certain key/values

I'm working with a plist file at the moment but intend to switch over to json when the backend is finally built. So for the moment my plist is an array that contains a bunch of dictionaries.
I'd like to use this information to create a new array containing only the dictionaries with certain values.
For example. My plist contains a bunch of locations like so:
key: location value:example place name here
key: type value:indoor
I want to build an array containing only those with "indoor" set as the type value.
And then perhaps a second one containing all "outdoor" locations.
What's the best way to go about doing this, or perhaps I can be directed to a tutorial of some sort.
Thanks.
Simply loop through your array and add the qualifying dictionaries to a new array.
NSMutableArray *arrayIndoor = [NSMutableArray array];
NSMutableArray *arrayOutdoor = [NSMutableArray array];
NSString *type;
for (NSDictionary *dict in arrayPList) {
type = [dict objectForKey:#"type"];
if ([type isEqualToString:#"indoor"])
[arrayIndoor addObject:dict];
else if ([type isEqualToString:#"indoor"])
[arrayOutdoor addObject:dict];
}
All you are really needing to do is sort the array into two arrays. There isn't a direct method that I have seen that will do this for you. My suggestion would be to use a fast enumeration over the array and conditionally break it into two new arrays.
NSMutableArray *locations = [[NSMutableArray alloc] init];
NSMutableArray *type = [[NSMutableArray alloc] init];
for (NSDictionary *dict in MyPlistArray) {
if ([dict valueForKey:#"locationKey"]) {
[locations addObject:dict];
} else if ([dict valueForKey:#"typeKey"]) {
[type addObject:dict];
}
}
You might need to use a different method for determining which key to put in each array, but you get the general idea.
Also I'm assuming that you would want the arrays of dictionaries to persist after, so you can just set those up as properties instead of local variables.

How can I alphabetically sort the values in my NSDictionary with an NSArray?

I have an NSDictionary which contains several arrays with several strings in them. I want to put all strings under each array in one single array. How can I receive all the strings at once? I've tried this:
NSMutableArray *mutarr = [[NSMutableArray alloc] initWithObjects:[self.firstTableView allValues], nil];
NSArray *mySorted = [[NSArray alloc]init];
mySorted = [mutarr sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
NSLog(#"First table view values: %#", mySorted);
NOTE: self.firsttableview is a NSDictionary like this:
NSString *path = [[NSBundle mainBundle] pathForResource:#"firstTableView" ofType:#"plist"];
self.firstTableView = [NSDictionary dictionaryWithContentsOfFile:path];
EFFECT: This gives me a list in NSLog, but it isn't in alphabetic order.
You are initializing your mutarr with one object which is the array returned by allValues on your dictionary. Instead try this:
NSMutableArray* mutarr = [NSMutableArray array];
for (NSArray* array in self.firstTableView.allValues) {
[mutarr addObjectsFromArray:array];
}
Your code is going to mean that mutarr is an array containing an array of arrays, not an array of strings. You should be looping over the array values from the dictionary and adding the items from each one to your mutarr to make it an array of strings that you can sort.
If your NSDictionary values are arrays then you are trying to sort the arrays instead of the strings. Try to create a for loop to iterate [self.firstTableView allValues] then add all values in that array to your main to sort array.

Dynamica string count in NSMutableArray in NSMutableDictionary

I am familiar with getting a string count from a known array
int numberOfWords = [self.wordArray count];
but I have an unknown number of strings in an unknown number of arrays, all referenced by a dictionary. This works - good.
NSMutableDictionary *eqClasses = [[NSMutableDictionary alloc] init];
The arrays and strings are added at runtime (with help of this board):
NSMutableArray* array = [eqClasses objectForKey:wordPattern];
if(!array) {
// create new array and add to dictionary if wordPattern not found
array = [NSMutableArray array];
[eqClasses setObject:array forKey:wordPattern];
}
[array addObject:tempWordStr];
Now I need to iterate through the dictionary and get the array with the largest word count. Is there a way to scroll through all the arrays in the dictionary without using a key (I won't know all the word patterns as they are generated dynamically), AND once I find the array with the most words, get that array/value and key/wordpattern?
Well, there is a way to get all the keys within a dictionary:
NSArray *keyArray = [myDict allKeys];
And then you just go through the array and get the object for each key.
A fast enumeration should work nicely.
for (NSString *string in NSArray){
...
} //Assuming your keys are strings!
You can save each string to a temporary string, and when encountering a new string, compare to find the longer one. If it's longer, replace the old string with the longer one.
Hope this helped! ^_^
^_^
Okay, so now that you have an array full of all the keys in the dictionary,
you can iterate through the entire array and get the corresponding value (the string) for each key.
NSArray *keyArray = [myDict allKeys]; //This gets all the keys
NSString *tempString = #""; //This is the string you will save the longest string in. It gets updated when a longer string is found in the following loop.
for (NSString *string in keyArray){
NSString *stringFromCurrentKey = [myDict objectForKey:string];
if(stringFromCurrentKey.length > tempString.length){
tempString = stringFromCurrentKey;
}
} //By the end, you should be left with the longest string contained in tempString!
^_^ Hope this made sense and helped!
Try this code:
NSArray *largestArray = nil;
for (NSString *key in dictionary)
{
NSArray *array = [dictionary objectForKey:key];
if (array.count > largestArray.count) // largestArray.count is 0 if largestArray is nil
{
largestArray = array;
}
}

Resources