NSPredicate for calculated field with NSDecimalNumber - objective-c

I want to filter a calculated field (binary expression in terms of Apple documentation) in Core Data with a NSDecimalNumber value.
The entity has two attributes: field1 and field2, both of type Decimal
The predicate is:
NSDecimalNumber *number = ...;
NSString *predicateString = #"(field1 + field2) <= %#";
NSArray *arguments = [NSArray arrayWithObjects:number, nil];
[NSPredicate predicateWithFormat:predicateString argumentArray:arguments];
But this doesn't work. It gives nothing back.
When i filter each Attribute alone then it works. For example:
NSString *predicateString = #"field1 <= %#"; //ok
NSString *predicateString = #"field2 <= %#"; //ok
What's wrong?

Related

Search through NSArray of objects with different locale

I have an array of phone number objects, the phone number model is as follows:
#property NSString *hotlineName;
#property NSString *hotlineNameAr;
#property NSString *hotlineNumber;
#property NSString *hotlineImage;
#property NSInteger hotlineID;
#property RLMArray<Tags> *hotlineTags;
when I perform a search, I filter the array if either hotlineName, hotlineNameAr, hotlineNumber and in property hotlineTags: tagName and tagNameAr contain the search text.
I used NSPredicate to filter the array as such:
-(void) searchForText: (NSString *) searchText{
NSString *predicateFormat = #"SELF.%K contains[cd] %#";
NSString *tagFormat = #"ANY SELF.hotlineTags.%K contains[cd] %#";
NSString *searchNameAttribute = #"hotlineName" ;
NSString *searchTagAttribute = #"tagName";
NSString *searchNameAttribute_ar = #"hotlineNameAr" ;
NSString *searchTagAttribute_ar = #"tagNameAr";
NSString *numberAttribute = #"hotlineNumber";
NSPredicate *namePredicate = [NSPredicate predicateWithFormat:predicateFormat, searchNameAttribute, searchText];
NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:tagFormat, searchTagAttribute, searchText];
NSPredicate *namePredicate_ar = [NSPredicate predicateWithFormat:predicateFormat, searchNameAttribute_ar, searchText];
NSPredicate *tagPredicate_ar = [NSPredicate predicateWithFormat:tagFormat, searchTagAttribute_ar, searchText];
NSPredicate *numberPredicate = [NSPredicate predicateWithFormat:predicateFormat, numberAttribute, searchText];
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:#[namePredicate, numberPredicate, tagPredicate, namePredicate_ar, tagPredicate_ar]];
filteredResults = [hotlines_arr filteredArrayUsingPredicate:predicate];
}
and so far it works well, the problem arose when I search with numbers in a different locale, in this instance in Arabic, so used I NSNumberFormatter as such:
// Convert string From Arabic/Persian numbers to English numbers
+(NSString *) convertToEnglishNumber:(NSString *) string {
// NSNumericSearch
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:#"EN"];
[formatter setLocale:locale];
NSNumber *number = [formatter numberFromString:string];
return [number stringValue];
}
but the problem with NSNumberFormatter is that any leading zero's are ignored in the conversion, so I need an alternative to format the NSString based on locale or search array while taking in consideration locale, the same option in spotlight search.
I also tried formatting as such but it was in vain.
NSString *str = [[NSString alloc] initWithFormat:#"%#" locale:locale, searchText];
NSString *localizedString =[NSString localizedStringWithFormat:#"%#", searchText];
As I couldn't think of any other option and this was a last resort, I ended up replacing the string but I'm very unhappy with answer:
+ (NSString *) replaceStrings: (NSString *) textToEdit{
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:#"ar"];
for (NSInteger i= 0; i < 10; i++) {
NSString *stringVal = [#(i) stringValue];
NSString *localeString = [#(i) descriptionWithLocale:locale];
textToEdit = [textToEdit stringByReplacingOccurrencesOfString:localeString withString:stringVal];
}
return textToEdit;
}

How to sort CoreData string attribute in descending order to find the highest current value?

I have a CordData store where the primary "key" is a string; I need to sort that key attribute into descending order so I can find the highest current key. I know I have to convert the key to an int for sorting, but from there I'm lost using comparators (I don't use them often enough to gain any meaningful experience with them). Here is my code so far (which is wrong, I know):
NSArray *sortedArray;
NSString *predicateString = [NSString stringWithFormat:#"sku > %d",0];
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString];
NSArray *skuRecord = [Books MR_findAllWithPredicate:predicate];
sortedArray = [skuRecord sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSString *first = [(Books*)a sku];
NSString *second = [(Books*)b sku];
return [first compare:second];
}];
What's being returned is '1', which is the lowest SKU. I have looked at SO and Google for hours, and found nothing which would help resolve this problem. Can someone please tell me what's wrong with my code? I would appreciate it.
UPDATE: this is the code I finally came up with:
NSString *predicateString = [NSString stringWithFormat:#"sku > %d",0];
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString];
NSArray *unsortedArray = [Books MR_findAllWithPredicate: predicate];
int highestSKU = 0;
for(int i = 0; i < unsortedArray.count; i++) {
Books *booksManagedObject = (id)unsortedArray[i]; // now in Books array to be able to access .sku
NSString *givenSKU = booksManagedObject.sku;
if([givenSKU intValue] > highestSKU)
highestSKU = [givenSKU intValue];
}
return [NSString stringWithFormat:#"%d",highestSKU];
The usual solution to the problem is to [temporarily] pad the character integer values on the left with zeros, which will cause them to sort correctly even as characters (without converting to integers). Don't know whether this is feasible in your particular instance but I've used that method before.
You can sort using NSSortDescriptors with strings, no need to convert to integers.
NSArray *unsortedArray = #[#"3",#"2",#"5",#"1",#"4"];
NSSortDescriptor *sorter = [NSSortDescriptor sortDescriptorWithKey:#"" ascending:NO];
NSArray *sortedArray = [unsortedArray sortedArrayUsingDescriptors:#[sorter]];
NSLog(#"First = %#, Last = %#",sortedArray[0],[sortedArray lastObject]);
Prints: First = 5, Last = 1
So either I'm missing something in your explanation or vice versa. Did you set ascending to NO?
Your code should look more like this I think;
NSArray *unsortedArray = [Books MR_findAllWithPredicate: predicate];
NSSortDescriptor *sorter = [NSSortDescriptor sortDescriptorWithKey:#"sku" ascending:NO];
NSArray *sortedArray = [unsortedArray sortedArrayUsingDescriptors:#[sorter]];
NSLog(#"First = %#, Last = %#",sortedArray[0],[sortedArray lastObject]);

Comparing NSDecimalNumber won't work?

For some reason, the comparing logic isn't working correctly... it wont compare two NSDecimalNumber objects. Sometimes it works, sometimes it doesn't. Really weird. The if statement works on some compilations, and sometimes not. Is this the right way of doing it?
The data is from a json file which is a 2 point decimal number which looks like this: 63.32
Why isn't this working correctly?
NSError * error;
NSDictionary * json = [NSJSONSerialization JSONObjectWithData:responceData options:kNilOptions error:error];
NSArray * latestPrice = [json objectForKey:#"data"];
NSLog(#"Latest price %#", latestPrice);
NSNumber * value = [(NSDictionary*)[latestPrice objectForKey:#"last_offer"] objectForKey:#"display"];
NSString * val = [[NSString alloc] initWithFormat:#"%#", value];
NSString * valFinal = [val stringByTrimmingCharactersInSet:[NSCharacterSet symbolCharacterSet]];
NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString:valFinal];
NSLog(#"%#", number);
NSString * val2 = [[NSString alloc] initWithString:#"44.14"];
NSDecimalNumber *number2 = [NSDecimalNumber decimalNumberWithString:val2];
if(number2 >= number){
NSLog(#"ds");
}
I need to compare the json value with a local value with the same decimal points.
NSDecimalNumber is an object. You tried to compare memory addresses.
Use compare: instance method of NSDecimalNumber.
if ([number compare:number2] == NSOrderedAscending)
NSDecimalNumber Class Reference

How to create a NSPredicate which filters all characters in given range including digits/numbers?

I want to implement full text search and what I do is this:
NSString* start = #"a";
NSString* stop = [start stringByAppendingString:#"zzz"];
NSArray* range = [NSArray arrayWithObjects:[NSExpression expressionForConstantValue:start],[NSExpression expressionForConstantValue:stop],nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY keyword.word BETWEEN %#",range];
Start is variable and changes depending what I type (i.e. if I type 'cool' it means start= #"cool" and stop will be #"coolzzz").
Now this works great until my input is a digit or number and the NSPredicate doesn't return any results even though there are.
For example in my data I have entries of shape entry_name 1, entry_name 2. If I input entry_name I get all results but as soon as I input entry_name 1 I get no results.
After testing I've seen that if I just enter 1 I get no results so the NSPredicate doesn't work.
How can I write an NSPredicate which filters all the characters including digits?
You don't need to create a range for the BETWEEN operator, a simple array is enough:
NSString* start = #"a";
NSString* stop = [start stringByAppendingString:#"zzz"];
NSPredicate *betweenPredicate = [NSPredicate predicateWithFormat: #"attributeName BETWEEN %#",
[NSArray arrayWithObjects:start, stop, nil]];
See also Predicate Programming Guide
NSString *searchText=#"string u want to search";
NSArray *range = [NSArray arrayWithObjects:#"entry_name 1",#"entry_name 2",#"entry_name 3",#"entry_name 4",#"entry_name5",nil];
NSMutableArray *match = [[NSMutableArray alloc] init];
for (int i=0; i<[range count];i++)
{
NSString *sTemp = [range objectAtIndex:i] ;
NSRange titleResultsRange = [sTemp rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
[match addObject:sTemp];
}
NSLog(#"match= %#",match);
use above code for searching.

how to match string portion with NSArray values in objective-c

I have following array and search string.
NSArray *values =[NSArray arrayWithObjects:#"abc",#"xyz",#"cba",#"yzx",nil];
NSString *search = #"startcba";
I want to search string's end part within an array elements. My expected search result will be #"cba". Please let me know how to find the desire value in array for giving search.
Thanks,
You can use NSPredicate to get the elements that satisfy your requirement.
NSPredicate * predicate = [NSPredicate predicateWithFormat:#" %# ENDSWITH SELF ", search];
NSArray * searchResults = [values filteredArrayUsingPredicate:predicate];
The NSPredicates way is great.
Here is an approach with rangeOfString:
NSArray *values =[NSArray arrayWithObjects:#"abc",#"xyz",#"cba",#"yzx",nil];
NSString *search = #"startcba";
NSUInteger searchLength = [search length];
NSString *result = nil;
for (NSString *val in values)
{
NSUInteger valLength = [val length];
NSRange expectedRange = NSMakeRange(searchLength - valLength, valLength);
NSRange rng = [search rangeOfString:val];
if ( rng.location == expectedRange.location && rng.length == expectedRange.length )
{
result = val;
break;
}
}