How do i find indexOfObject in an array that has dictionaries - ios

Here is my array :
<__NSCFArray 0x7b6ca390>(
{
name = kumar;
no = 158;
},
{
name = rajdeep;
no = 338;
},
{
name = smitha;
no = 361;
},
{
name = uma;
no = 422;
}
)
This is what I am trying to do
NSInteger selectedIndexpath=[self.arrLoadCell indexOfObject:_txtfield.text];
where
_txtfield.text = #"rajdeep"
and i get some random junk value like 2147483647 stored in selectedIndexPath.
Am i missing something? Or is there anyother way to handle it?

This "junk value" seems to be NSNotFound, which you should check against when using this method. Long story short, your array does not contain the value you are looking for. It does not work, because you are looking for a string but the array contains dictionaries, so you would have too search for e.g. { "name" : "rajdeep", "no" : #338 }.
Alternatively, to make this work with strings only, use NSPredicate for filtering, e.g.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == %#", valueFromTextbox];
NSArray result = [array filteredArrayUsingPredicate: predicate];
If your array is very short you can also make a loop for comparison.
Update to get the index, use the result of the predicate as input, e.g.
NSInteger selectedIndexpath = [self.arrLoadCell indexOfObject:result.firstObject];

indexOfObject: requires the actual object that is stored in the array. You are providing only the value of a key for one of the Dictionaries.
One of the ways you could achieve what you want, is to loop through the array and for each dictionary, test the value.
The "junk value" you got is NSNotFound, which means that the object was not found.

That's because your array contains Dictionaries, not Strings. You cannot compare your String (textfield.text) with the dictionaries that are in your array.

I think what you want is:
int idx = NSNotFound;
for (int i=0; i<self.arrLoadCell.count; i++) {
NSDictionary *dict = [self.arrLoadCell objectAtIndex:i];
if ([[dict objectForKey:#"name"] isEqualToString:_txtfield.text]) {
idx = i;
break;
}
}
NSInteger selectedIndexpath=idx;

NSUInteger indexPath = 0;
for (NSDictionary *dic in arrLoadCell){
if ([[dic objectForKey:#"name"] isEqualToString: _txtfield.text]) {
indexPath=[arrLoadCell indexOfObject:dic];
break;
}
}
NSLog(#"%lu is the indexPATH",(unsigned long)indexPath);
Assuming that your array of dictionaries is arrLoadCell this should work.

Related

ordering array with another array

I have the following categoryNames array.
And now, I have categoryTempElements and it has cName property. I need to know how to order categoryTempElements with a order of categoryNames.
UPDATE: I have added sortOrder property to Category object and tried the following but order does not change.
for (Category* a in categoryTempElements) {
int index = (int)[categoryNames indexOfObject:a.cName];
a.sortOrder = index;
}
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"sortOrder" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [categoryTempElements sortedArrayUsingDescriptors:sortDescriptors];
Another way could be without using sortedArrayUsingComparator, using two for-loops. Declare a new Mutable array called sortedCategoryElements and compare the categoryNames in categoryTempElements, If matches add it to a new array sortedCategoryElements:
NSMutableArray *sortedCategoryElements = [NSMutableArray new];
for (NSString *name in categoryNames) {
for (Category *category in categoryTempElements) {
if (name == category.cName) {
[sortedCategoryElements addObject:category];
break;
}
}
}
I tried with your set of data, it worked for me.
Hope it helps!
You need first convert your categoryNames array into dictionary with NSString key and NSNumber int value, the value will be the order in the array
//this is example code, this will be your first array (reference value array)
NSArray * array = #[#"prueba",#"prueba2",#"prueba3"];
//first you need convert this array in NSDictionary
NSMutableDictionary * arrayDict = [NSMutableDictionary dictionary];
int counter = 0;
for (NSString * value in array) {
if(arrayDict[value] == nil)
{
arrayDict[value] = [NSNumber numberWithInt:counter];
}
counter++;
}
After that then you can get the value and order with sortedArrayUsingComparator method, something like this
//this is an example of your second array categoryTempElements
NSArray * arrayOfObjs = #[[testObject testObjectWithName:#"prueba3"],[testObject testObjectWithName:#"prueba"],[testObject testObjectWithName:#"prueba2"]];
NSArray * sorted = [arrayOfObjs sortedArrayUsingComparator:^NSComparisonResult(testObject * _Nonnull obj1, testObject * _Nonnull obj2) {
if([((NSNumber*)arrayDict[obj1.cName]) intValue] < [((NSNumber*)arrayDict[obj2.cName]) intValue]){
return NSOrderedAscending;
}
if([((NSNumber*)arrayDict[obj1.cName]) intValue] > [((NSNumber*)arrayDict[obj2.cName]) intValue]){
return NSOrderedDescending;
}
return NSOrderedSame;
}];
for (testObject * obj in sorted) {
NSLog(#"%#",obj.cName);
}
And voila in sorted you will have your array of object sorted by your first array NSString order
Hope this helps
Create a dictionary with cName as the key and the Category object as the value. Then iterate over the categoryNames array, and build another array by using each item in categoryNames as the key. The resulting array should be sorted in the same order as categoryNames.
NSArray has a method sortedArrayUsingComparator: which sorts an array using the ordering implemented by the block you pass. This block, of type NSComparator, is passed references to two elements of your array and you must return the order of those two elements.
And now, I have categoryTempElements and it has cName property.
So your block will be passed two categoryTempElements, you need to access the cName property of each, and compare the resulting two values...
I need to know how to order categoryTempElements with a order of categoryNames
by the position, i.e. the index, of those values in your categoryNames array. The method indexOfObject: provides that index for you.
So put that together and your problem is solved.
HTH

iOS NSDictionary Values

I have an array of NSDictionaries and i can access the values in them just fine but i am trying to filter these dictionaries down based on a user's search (user can only search by the dictionary key (#"uniqueSignName").
Once the user has searched through the names property i then need to display ALL dictionary associated data for that #"uniqueSignName" value.
I do the following code and always get the correct amount of NSLogs. For the life of me i cannot remember how to GET those dictionaries.
for (int i = 0; i < [filteredDictionaries count]; i++) {
if ([[[filteredDictionaries valueForKey:#"uniqueSignName"] objectAtIndex:i] isEqualToString:[self.filteredResults objectAtIndex:indexPath.row]]) {
NSLog(#"Power Rangers");
}
}
Eg: I search for "John"
NSLog: #"Power Rangers"
Correctly only appears once.
Now, how do i access another property of "John's" dictionary?
If you want to search the name then better way is that to use NPredicate without iterating the array.
Please see the below example..it may help you...
// Here array is your main array...
NSArray *filteredarray = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"(uniqueSignName == %#)", #"John"]];
So the problem is solved, I can now access all the filtered properties.
for (NSDictionary *dict in filteredDictionaries) {
if ([[self.filteredResults objectAtIndex:indexPath.row] isEqualToString: dict[#"uniqueSignName"]]) {
NSString *myString = [NSString stringWithFormat:#"%#", dict[#"pType"]];
NSLog(#"hugh: %#", myString);
myString = displayPtype;
}
}

How to remove item from NSArray depending on the items contents

I am creating an NSArray of NSStrings, however one of the arrays that is entered is a set of quotation marks:
""
I would like to know hot to exclude these from my array, I have tried using a predicate but it's not working.
This is what my code looks like:
NSString *tempSymbolsString = [tempAxesDictionary objectForKey:#"Symbols"];
NSArray *tempSymbolsArray = [tempSymbolsString componentsSeparatedByString:#";"];
tempSymbolsArray = [symbolsArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF != """""]];
NSLog(#"%#", tempSymbolsArray);
Actually is even simpler than this. Since you only got strings in your array, create a mutable copy and remove all occurrences of "". Something like this perhaps:
NSMutableArray *temp = [tempSymbolsArray mutableCopy];
[temp removeObject:#"\"\""];
This works since removeObject: will compare objects via isEqual: and remove any matches.
Do it yourself:
NSString *tempSymbolsString = tempAxesDictionary[#"Symbols"];
NSMutableArray *symbolsArray = [[tempSymbolsString componentsSeparatedByString:#";"] mutableCopy];
for (NSUInteger i = symbolsArray.count; i > 0; i--) {
if ([symbolsArray[i - 1] isEqualToString:#"\"\""]) {
[symbolsArray removeObjectAtIndex:i - 1];
}
}
At the end the symbolsArray will have all values except those matching "".
BTW - your original predicate probably needs a bunch of escaping:
[NSPredicate predicateWithFormat:#"SELF != \"\\\"\\\"\""]

How to properly filter a NSArray using a NSPredicate

I am trying to find the tags inside a NSDictionary inside myAr that matches the criteria of str and I want the result that has only those exact arrays no more nor less. In this example I want only the 2nd NSDictionary of myAr.
I though of trying to achieve this by using a predicate but that always returns empty when i use arrays.
I am trying to filter using an array but this is not working. I was wondering if anyone could tell me what i am doing wrong and how could i achieve my objective. thanks in advance
NSArray * myAr = #[ #{ #"tags": #[#"one",#"two",#"three"],
#"number": #"4"
},
#{ #"tags": #[#"one",#"two"],
#"number":#"4"
},
#{ #"tags": #[#"one",#"two",#"four"],
#"number":#"4"
},
#{ #"tags": #[#"chacho",#"chocho"],
#"number":#"4"
},
#{ #"tags": #[#"one"],
#"number":#"4"
} ];
NSArray* str = #[#"one",#"two"];
NSPredicate* pre = [NSPredicate predicateWithFormat:#"tags CONTAINS %# ",str];
myAr = [myAr filteredArrayUsingPredicate:pre];
NSLog(#"%#",myAr);
If I understand your question correctly, you just have to replace "CONTAINS" by "="
in the predicate:
[NSPredicate predicateWithFormat:#"tags = %# ",str]
This gives an array with all dictionaries where the "tags" value is equal to the
given array str. In your example, it returns an array with the second dictionary
only.
UPDATE: To find all dictionaries where the "tags" value is an array with the
given elements, but independent of the order, the following slightly more
complicated predicate should work:
[NSPredicate predicateWithFormat:#"tags.#count = %d AND SUBQUERY(tags, $t, $t in %#).#count = %d",
[str count], str, [str count]];
UPDATE 2: That was too complicated, the following predicate seems to work as well:
[NSPredicate predicateWithFormat:#"tags.#count = %d AND ALL tags in %#",
[str count], str]
(I have assumed that str contains only different elements.)
For an answer that uses neither a for loop nor predicate format strings, try using a block and make use of NSSet to determine if the set of tags you want to match is equal to a set of the array element's tags. For example:
NSSet* desiredTags = [NSSet setWithObjects:#"one", #"two", nil];
NSPredicate *tagFilterPredicate = [NSPredicate
predicateWithBlock:^BOOL (id data, NSDictionary *bindings) {
NSSet *tags = [NSSet setWithArray:[data objectForKey:#"tags"]];
return [desiredTags isEqual:tags];
}];
NSArray *resultArray = [myArr filteredArrayUsingPredicate:tagFilterPredicate];
Bear in mind that this does allocate a set per iteration. So, if you're looking to avoid allocations, this is not adequate. Otherwise, it at least avoids a format string.
A brute-force way to do this would be to remove your predicate and just enumerate:
NSArray *required = #[#"one", #"two"];
NSMutableArray *matches = [#[] mutableCopy];
[myAr enumerateObjectsUsingBlock:^(NSDictionary *dict, NSUInteger idx, BOOL *stop) {
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSArray class]]) {
BOOL match = YES;
for (NSString *item in required) {
if (![obj containsObject:item]) {
match = NO;
break;
}
}
if (match && [(NSArray *)obj count] == required.count) {
[matches addObject:obj];
}
}
}];
}];

NSPredicate check NSArray if object has one of several ID

Little diifficult to explain but I am trying to use NSPredicate for filtering an array with custom NSManagedObject by ids. I have a server that can send update, delete or add new objects, and I need to control if those objects from the JSON file already exist, if exist just update them or insert to core data if not.
I am using this predicate now :
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"storeId != %#", [jsonFile valueForKey:#"Id"];
Where jsonFile contains unparsed Store objects. But with this predicate, it will give me a huge array, since one id will be unlike some storeId, and next id will match.
Json file is some sort of this :
"Stores":[{
"id":1,
"name":"Spar",
"city":"London"
}
{
"id":2,
"name":"WalMart",
"city":"Chicago"
}];
I am not sure if I understand correctly what you are trying to achieve, but perhaps you can use the following:
NSArray *jsonFile = /* your array of dictionaries */;
NSArray *idList = [jsonFile valueForKey:#"id"]; // array of "id" numbers
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"NOT(storeId IN %#)", idList];
This will give all managed objects that have a storeId that is not equal to any of the ids in the jsonFile array.
The syntax of the predicate is probably off - someone else may suggest a fix - but if you have an array, why not use
- (NSUInteger)indexOfObjectPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
since its much easier:
NSInteger textID = ... // you set this
NSInteger idx = [myArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop))
{
NSInteger objIdx = [obj objectForKey:#"id"] integerValue]; // integerValue works for both NSNUmbers and NSStrings
if(objIdx == testID) {
return YES;
*stop = YES;
}
}

Resources