Check if an object exist in a NSMutableArray of NSDictionary - ios

i have an NSMutableArray that contains some NsDictionary with NSstring for differents Keys.
Somethings like:
NSDictionary *ExempleDictionary = [NSDictionary dictionaryWithObjectsAndKeys:[Date objectAtIndex:sender.tag],#"DATE",[Time objectAtIndex:sender.tag],#"TIME", nil];
I'd like to check if a particular object with DATE=xxx && TIME=xxx exist in the Array.
Any idea?!

You can do the search with NSPredicate:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.DATE=%# AND SELF.TIME=%#", dateVal, timeVal];
NSArray *filteredArray = [myArray filteredArrayUsingPredicate:predicate];
filteredArray contains an NSArray of all NSDictionary objects matching the specified date and time condition. You can retrieve the matching objects by iterating the filtered array.

You can use NSArray's containsObject: (if you have a reference to the dictionary laying around) or indexOfObjectIdenticalTo: (if you want to check if an element identical to the one you are passing -but not necessarily the same object- is in the array).
Both are explained in the docs:
containsObject
indexOfObjectIdenticalTo

Related

How to use a NSPredicate to filter an array of objects that contain NSMetadataitems

I have a class. Lets call that class MyObject. MyObject has a property called item that is a NSMetadataItem.
NSMetadataItems have an attribute called NSMetadataItemFSNameKey that can be fetched by using this:
NSString *fileName = [myMetadataItem valueForAttribute: NSMetadataItemFSNameKey];
Now I have an array or MyObjects and I want to find what object has an item which NSMetadataItemFSNameKey is the one I am looking for.
OK, I can iterate thru the array using this code:
for (MyObject *oneObj in array) {
NSString *oneFileName = [oneObj.item valueForAttribute:NSMetadataItemFSNameKey];
if ([oneFileName isEqualToString:fileNameItem]) {
// found, do something
}
}
but I am trying to find if it is possible to do that using NSPredicates and filtering?
Is that possible?
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"item.%K = %#", NSMetadataItemFSNameKey, fileNameItem];
NSArray *filteresArray = [array filteredArrayUsingPredicate:predicate];
Typed in Safari.

nsdictionary with arrays nspredicate filtering

I have a tableview that i want to search through with a searchable. It worked before but when i added sections i got into trouble because i had to change from arrays to dictionary.
So basically i have a NSDictionary that looks like this
{ #"districtA": array with point objects, #"districtB": array with point objects}
I need to filter them based on the point objects.name that is in the arrays. After that i want to create a new nsdictionary with the filtered objects in it.
I tried at least 10 different methods but i can't figure it out so i think this is the only way that i am most positive that should work.
This is the only way i can think of if there is an easier way or more logic way please tell me.
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.name BEGINSWITH[c] %#",searchText];
//create new array to fill
NSArray *arrayWithFilteredPoints = [[NSArray alloc] init];
//loop through the values and put into an rray based on the predicate
arrayWithFilteredPoints = [NSArray arrayWithObject:[[self.PointList allValues] filteredArrayUsingPredicate:predicate]];
NSMutableDictionary *dict = [#{} mutableCopy];
for (Point *point in arrayWithFilteredPoints) {
if (![dict objectForKey:Point.district])
dict[Point.district] = [#[] mutableCopy];
[dict[Point.district]addObject:Point];
}
self.filteredPointList = dict;
self.filteredDistrictSectionNames = [[dict allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];}
This results in a crash, it happens of course where the predicate is used but i don't know how to debug what predicate i should use:
on 'NSInvalidArgumentException', reason: 'Can't do a substring operation with something that isn't a string (lhs = (
West ) rhs = w)'
I have read the comments and you are right. There was something wrong with my code.
I changed the logic, i added some more steps (like creating NSArray without needing it) to make the solution clear
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.name BEGINSWITH[c] %#",searchText];
//1. create new array to fill only the Points from the dictionary
NSArray *allPoints = [self.PointList allValues];
NSMutableArray *allPointObjects = [[NSMutableArray alloc]init];
for (NSArray *array in allPoints) {
for (Point *point in array) {
[allPointObjects addObject:point];
}
}
//2. loop through allPointObjects and put into an mutablearray based on the predicate
NSArray *arrayWithFilteredPoints = [[NSArray alloc] init];
arrayWithFilteredPoints = [allPointObjects filteredArrayUsingPredicate:predicate];
NSMutableDictionary *dict = [#{} mutableCopy];
for (Point *point in arrayWithFilteredPoints) {
if (![dict objectForKey:point.district])
dict[point.district] = [#[] mutableCopy];
[dict[point.district]addObject:Point];
}
self.filteredPointList = dict;
self.filteredDistrictSectionNames = [[dict allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
I wanted a filtered nsdictionary at the end that i can pass back to my tableview that reads the dictionary objects based on the keys (districts)
It seems clear from your description that [self.PointList allValues] is not an array of Point objects but an array of arrays of Point objects. That is the source of your difficulty, including your original crash.
You need to decide what to do about that; for example, if you want just one big array of Point objects, then flatten the array of arrays before you filter. I can't advise you further because it is not obvious to me what ultimate outcome you desire.
EDIT You've now modified your code and I can see more clearly what you're trying to do. You have a dictionary whose values are arrays of points, and you are trying to filter some of the points out of each array. What I would have done is to do that - i.e., run thru the keys, extract each array, filter it, and put it back (or delete the key if the array is now empty). But I can see that what you are doing should work, because you have cleverly put the keys into the points to start with, so you can reconstruct the dictionary structure from that.

Filter an array with other array

I've got 2 arrays:
array1 contains objects of type object1. object1 has a property id.
array2 contains objects of type object2. object2 has a property object1Id.
I know, that array2 contains objects with ids which always are in array1, but array1 can have more (or equal) objects.
To show it:
So to simplify: array1 has all objects, array2 has new objects. How to get an array with old objects..? I'm trying to do it with predicate, but it feels odd to do a loop and insert each object1Id to the predicate. Is there any other option? How to do it properly?
You can use a predicate, and you don't need a loop if you use KVC.
Get the array of ids that should be excluded:
NSArray *excludeIds = [array2 valueForKey#"object1Id"];
Create the predicate:
NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:#"NOT (id IN %#)", excludeIds];
Then filter:
NSArray *oldObjects = [array1 filteredArrayUsingPredicate:filterPredicate];
It looks like you are trying to perform a set operations. What can be helpful is NSMutableSet class. Use setWithArray to create sets. Then use methods like:
unionSet:
minusSet:
intersectSet:
setSet:
To get subsets that match your criteria.
Source: NSMutableSet Class Reference
Hope it helps.
NSArray* oldIds = [array2 valueForKeyPath:#"object1Id"];
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"NOT (id IN %#)", oldIds];
NSArray* objects = [array1 filteredArrayUsingPredicate:predicate];

Updating NSDictionary inside an NSArray

I have a NSArray of NSDictionaries. I need the updated NSArray of NSDictionaries with value of one of the dictionary key updated with new value.
Please see below the NSArray structure. I want to update the value for Key3 inside this structure if Key1 matches with some value (e.g. 2). What would the fastest way of doing this. I do not want to use traditional For loop.
[myArray valueForKeyPath:#"#unionOfObjects.Key3"];
<__NSCFArray 0xe70c10>(
{
Key1 = 1;
Key2 = "New Location";
Key3 = (
Data1,
Data2,
Data3
);
},
{
Key1 = 2;
Key2 = "Old Location";
Key3 = (
Data1,
Data2,
Data4
);
}
)
We can solve it by using predicates:
NSArray *dictionaryArray;
NSNumber *key =#2;
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"Key1=%#",key];
NSArray *result =[dictionaryArray filteredArrayUsingPredicate:predicate];
result array now has all dictionaries having (key1 = 2)
Dictionarys can't be edited directly, they must be NSMutableDictionary to edit. Assuming they are NSMutableDictionary instances:
NSMutableDictionary *dic =result[0];
[dic setObject:someObject forKey:#"key3"];
Let's suppose that you already have an array containing all mutable dictionaries. The first step is to get what dictionaries you need to change:
NSPredicate* predicate= [NSPredicate predicateWithFormat: #"Key1=2"];
NSArray* filteredArray= [myArray filteredArrayUsingPredicate: predicate];
The second step is to replace the Key3 value for each object in the array. If you execute a selector on an array, and NSArray doesn't respond to that selector, the selector is performed on it's objects:
[filteredArray performSelector: #selector(setValue:forKey:) withObject: someValue withObject: #"Key3"];
After this statement you don't need to replace any object in myArray, because the filtered array contains the same objects that are in myArray, which are mutable dictionaries.
I would also go for predicates as #santhu stated on his answer. However, I want to point that when searching an unsorted array linear search (that is, looping through every object and checking if it's the wanted one) is optimal. Probably predicates will provide an speed-up due to their internal routines, but a predicate will still execute the "traditional for loop" you want to avoid and thus the speed-up will not be very significant.
There are other searching algorithms which provide a significant speed-up, but they are only valid for sorted databases (unless you have a quantum iPhone ;) ).
If you are interested on this topic, here you can find some types of search algorithms with an analysis of their complexity.

sort NSDictionary based on single object key

I would like some help sorting an NSArray of NSDictionary values based on each objects ISV key.
This is the code I have so far for creating my array objects so you have a better idea of what I am trying to do.
NSArray *combinedKeysArray = [NSArray arrayWithObjects:#"HASM", #"ISL", #"ISV", nil];
valuesCombinedMutableArray = [NSMutableArray arrayWithObjects:[dict objectForKey:#"HASM"],
[dict objectForKey:#"ISL"],
[dict objectForKey:#"ISV"],
nil];
combinedDictionary = [NSDictionary dictionaryWithObjects:valuesCombinedMutableArray
forKeys:combinedKeysArray];
[unSortedrray addObject:combinedDictionary];
// how do I then sort unSortedArray by the string values in each object ISV key?
any help would be greatly appreciated.
This can solve your problem
How to sort an NSMutableArray with custom objects in it?
https://stackoverflow.com/a/805589/1294448
You can use NSSortDescriptor to sort NSArays
Then in NSArray you have a method called sortedArrayUsingDescriptors
Or NSComparisonResult ca also be helpful some time http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html#//apple_ref/doc/uid/20000138-BABCEEJD
you won't be able to sort unSortedArray because it will only have one element in it (ie in your last line of code you are adding a single object by addObject).
That said, you cannot sort the dictionary either.. b/c dictionaries are unsorted by definition.
you can iterate over the keys of the dictionary in a specific order though, you can sort an array containing the keys of the dictionary.
NSArray *keys = [theDictionary allKeys];
NSArray *sortedKeys = [keys sortedArrayUsingSelector:#selector(compareMethod:)];
You can use -sortedArrayUsingComparator: to sort any way you need.
[unSortedrray sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *dict1, NSDictionary *dict2) {
return [[dict1 objectForKey:#"ISV"] localizedCompare:[dict2 objectForKey:#"ISV"]];
}];

Resources