NSPredicate to match string with an array of prefixes - objective-c

I'm unsure how to write this NSPredicate to achieve the following. I have an array of prefixes, and I want to know if any of them (plus an underscore) are the prefix of a given string. I don't need to know which matched, just a yes/no if any matched at all.
I can't seem to work this out, at the moment I have this
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
NSArray *bins = #[#"aaa", #"bbb", #"ccc"];
NSString* item = #"aaa_blah";
NSPredicate *pred = [NSPredicate predicateWithFormat:#"%# BEGINSWITH SELF", item];
NSLog(#"%#", [[bins filteredArrayUsingPredicate:pred] count] ? #"YES" : #"NO");
}
}
The only way I could think of doing it was filtering the array - so firstly is there a better approach?
And secondly, I want it to return true only if the prefix is followed by an underscore so
#[#"aaa", #"bbb", #"ccc"];
#"aaa_blah"; // YES
#"aaablah"; // NO
#"bbbblah"; // NO
I'm not sure how to do that?

+(void)checkIfExists:(NSArray *)prefixes inMyobjects:(NSArray *)myObjects withDivider:(NSString *)divider
{
divider = #"_";
prefixes = #[#"aaa",#"bbb",#"ccc"];
myObjects = #[#"aaa_sd",#"dsf_ds",#"aaa_sss",#"aaabbb"];
NSMutableArray * resultsOfPredicate = [NSMutableArray new];
for (NSString * pre in prefixes)
{
NSString * iAmLookingFor = [NSString stringWithFormat:#"%#%#", pre, divider];
NSPredicate *prefixPredicate = [NSPredicate predicateWithFormat:#"SELF beginsWith[c] %#", iAmLookingFor];
NSArray * resultOfSearch = [myObjects copy];
resultOfSearch = [resultOfSearch filteredArrayUsingPredicate:prefixPredicate];
NSLog(#"ros %#",resultOfSearch);
[resultsOfPredicate addObject:#([resultOfSearch count])];
}
for (int i = 0; i<[resultsOfPredicate count]; i++)
{
NSLog(#"prefix %# isAppeared:%d",[prefixes objectAtIndex:i], [[resultsOfPredicate objectAtIndex:i] boolValue]);
}
}
I hope this will help.

Related

search NSArray with regex

I have an array of names. If any of the name is already there then on inserting new name I want to append the counter eg John (02) if John already present in array then John (03) if it is third entry of name John.
Is there any way to filter array with Regex so that I can filter all records with pattern "John (xx)"?
Yup. You have to loop through the array and check with regex. You have to do this, since if you just check if the array contains your string, it won't return true if you search for "John" and the only one in your array is "John1"
NSMutableArray *testArray = [[NSMutableArray alloc] initWithObjects:#"John", #"Steve", #"Alan", #"Brad", nil];
NSString *nameToAdd = #"John";
NSString *regex = [NSString stringWithFormat:#"%#[,]*[0-9]*", nameToAdd];
NSPredicate *myTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", regex];
for (int i = 0; i < [testArray count]; i++)
{
NSString *string = [testArray objectAtIndex:i];
if ([myTest evaluateWithObject:string])
{
// Matches
NSLog(#" match !");
int currentValue;
NSArray *split = [string componentsSeparatedByString:#","];
if ([split count] == 1)
{
// Set to 2
currentValue = 2;
}
else
{
currentValue = [[split objectAtIndex:1] intValue];
currentValue++;
}
NSString *newString = [NSString stringWithFormat:#"%#,%d", nameToAdd, currentValue];
[testArray replaceObjectAtIndex:i withObject:newString];
}
}
for (NSString *string in testArray)
{
NSLog(#"%#", string);
}
This will replace "John" with "John,2", and if you search for "John" a third time it will replace it with "John,3".
Hope this helps
You can create a predicate for your regular expression and then filter the array using the predicate. Based on the count of the matches, you can update the new value being added as needed.
NSMutableArray *currentNames = ... // the current list of names
NSString *newName = ... // the new name to add
NSString *regex = [NSString stringWithFormat:#"%# \\([0-9]*\\)", newName];
NSPredicate *filter = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", regex];
NSArray *matches = [currentNames filteredArrayUsingPredicate:filter];
if (matches.count) {
NSString *updatedName = [NSString stringWithFormat:#"%# (%02d)", newName, matches.count];
[currentNames addObject:updatedName];
} else {
[currentNames addObject:newName];
}
You can filer an array with NSPredicate. Not too familiar with regex, but the following seems okay:
NSArray *array = #[#"John (01)", #"John (02)", #"John XX"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF MATCHES 'John [(]\\\\d{2}[)]'"];
NSArray *result = [array filteredArrayUsingPredicate:predicate];
NSLog( #"%#", result ); // Output John (01), John (02)

Objective-C: How to find the most common string in an array?

I have an array of strings from an online database that I trying to determine the most commonly used word. The values inside the arrays will vary but I want to check the most common words of whatever collection or words I'm using. If theoretically I had an array of the following...
NSArray *stringArray = [NSArray arrayWithObjects:#"Duck", #"Duck", #"Duck", #"Duck", #"Goose"];
How do I iterate through this array to determine the most common string, which would obviously be "Duck"?
Simplest way is probably NSCountedSet:
NSCountedSet* stringSet = [[NSCountedSet alloc] initWithArray:strings];
NSString* mostCommon = nil;
NSUInteger highestCount = 0;
for(NSString* string in stringSet) {
NSUInteger count = [stringSet countForObject:string];
if(count > highestCount) {
highestCount = count;
mostCommon = string;
}
}
You can use the word as a key into a dictionary.
NSMutableDictionary *words = [NSMutableDictionary dictionary];
for (NSString *word in stringArray) {
if (!words[word]) {
[words setValue:[NSDecimalNumber zero] forKey:word];
}
words[word] = [words[word] decimalNumberByAdding:[NSDecimalNumber one]];
}
Now iterate through words and find the key with the highest value.
NSString *mostCommon;
NSDecimalNumber *curMax = [NSDecimalNumber zero];
for (NSString *key in [words allKeys]) {
if ([words[key] compare:curMax] == NSOrderedDescending) {
mostCommon = key;
curMax = word[key];
}
}
NSLog(#"Most Common Word: %#", mostCommon);
EDIT: Rather than looping through the array once then looping separately through the sorted dictionary, I think we can do better and do it all in a single loop.
NSString *mostCommon;
NSDecimalNumber *curMax = [NSDecimalNumber zero];
NSMutableDictionary *words = [NSMutableDictionary dictionary];
for (NSString *word in stringArray) {
if (!words[word]) {
[words setValue:[NSDecimalNumber zero] forKey:word];
}
words[word] = [words[word] decimalNumberByAdding:[NSDecimalNumber one]];
if ([words[word] compare:curMax] == NSOrderedDescending) {
mostCommon = word;
curMax = words[word];
}
}
NSLog(#"Most Common Word: %#", mostCommon);
This should be significantly faster than my answer pre-edit, though I don't know how it compares to using the NSCountedSet answer.
Try using NSPredicate.
NSUInteger count=0;
NSString *mostCommonStr;
for(NSString *strValue in stringArray) {
NSUInteger countStr=[[stringArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self MATCHES[CD] %#, strValue]]count];
if(countStr > count) {
count=countStr;
mostCommonStr=strValue;
}
}
NSLog(#"The most commonstr is %#",mostCommonStr);

NSPredicate Crashes when trying to use CONTAINS

The data structure that I want to question. Data is a Transformable field which in turn is a NSDictionary.
Obj = { //...
NSDictionary *data:#{
likesPeople:#[#{#"username":#"jack",#"id":#"ae3132"}]
}
}
what I want to do is search inside the NSArray *fetchResult to check that there is noone in likesPeople with X id .
My attempts on doing this always end up crashing highlighting that there is a problem in my NSPredicate declaration.
What am I doing wrong and How could I effectively fetch the information that I want?
SocialWall *theSocialWall = fetchResult[0];
NSLog(#"%#",theSocialWall.data);
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"data.likesPeople CONTAINS(c) %#",myUser.userWebID];
NSArray * result = [fetchResult filteredArrayUsingPredicate:predicate];
NSLog(#"%#",result);
not Contains(c) but Contains[c]
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
NSDictionary *d = #{#"key":#"hi my name dominik pich"};
NSArray *a = #[d];
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"key CONTAINS[c] %#",#"dominik"];
NSArray * result = [a filteredArrayUsingPredicate:predicate];
NSLog(#"%#",result);
}
}

NSPredicate of multidimensional NSArray

Given is an NSArray with objects, each of which has an NSArray with floats, stored as NSNumbers.
I am trying to create an NSPredicate to filter my main array based on the float values. So, for instance, how to get all objects that have the value 234.6 +/- 0.8 as one of the floats in the sub-array?
I can do something like this for a one-dimensional NSArray of floats:
float targetFloat = 234.6;
float delta = 0.8;
filterPredicate = [NSPredicate predicateWithFormat: #"myFloat > %f AND myFloat < %f", (targetFloat - delta), (targetFloat + delta)];
filteredArray = [originalArray filteredArrayUsingPredicate: filterPredicate];
But how do I change it for my 2D NSArray with NSNumbers?
You can use "SELF[index]" in a predicate to access specific elements of the sub-array.
The following predicate finds all sub-arrays where the first element is in the
specified range:
float lowValue = 1.5;
float hiValue = 2.5;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF[0] > %f AND SELF[0] < %f", lowValue, hiValue];
NSArray *filtered = [array filteredArrayUsingPredicate:predicate];
If you want to find the sub-arrays that contain any number in the specified range, use
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY SELF BETWEEN %#", #[#(lowValue), #(hiValue)]];
Your predicate can access the object's property that holds the array by name; I've called this list in the example below. Then use the ANY keyword to check all the values in the array, and BETWEEN to find out if those values are within your chosen range.
#import <Foundation/Foundation.h>
#interface Grumolo : NSObject
#property (copy, nonatomic) NSArray * list;
#end
#implementation Grumolo
- (NSString *)description
{
return [NSString stringWithFormat:#"%#: %p, list: %#", NSStringFromClass([self class]), self, [self list]];
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
float target = 234;
float delta = 0.8;
NSPredicate * p = [NSPredicate predicateWithFormat:#"ANY list BETWEEN %#", #[#(target-delta), #(target+delta)]];
NSArray * yes = #[#234, #10, #100];
NSArray * yes2 = #[#0, #16, #234];
NSArray * no = #[#1, #2, #3];
Grumolo * g1 = [Grumolo new];
[g1 setList:yes];
Grumolo * g2 = [Grumolo new];
[g2 setList:yes2];
Grumolo * g3 = [Grumolo new];
[g3 setList:no];
NSLog(#"%#", [#[g1, g2, g3] filteredArrayUsingPredicate:p]);
}
return 0;
}
You might also like to try predicateWithBlock:, which would let you express what you're trying to do with a traditional loop over each array, returning YES if you find an element that meets your criteria and NO if you exhaust the list.
NSPredicate * pb = [NSPredicate predicateWithBlock:^BOOL(Grumolo * evaluatedObject, NSDictionary *bindings) {
NSArray * list = [evaluatedObject list];
__block BOOL result = NO;
[list enumerateObjectsUsingBlock:^(NSNumber * obj, NSUInteger idx, BOOL *stop) {
BOOL moreThanLower = (NSOrderedDescending == [obj compare:#(target-delta)]);
BOOL lessThanUpper = (NSOrderedAscending == [obj compare:#(target+delta)]);
if( moreThanLower && lessThanUpper ){
*stop = YES;
result = YES;
return;
}
}];
return result;
}];

Sort characters in NSString into alphabetical order

I'm trying to re-arrange words into alphabetical order. For example, tomato would become amoott, or stack would become ackst.
I've found some methods to do this in C with char arrays, but I'm having issues getting that to work within the confines of the NSString object.
Is there an easier way to do it within the NSString object itself?
You could store each of the string's characters into an NSArray of NSNumber objects and then sort that. Seems a bit expensive, so I would perhaps just use qsort() instead.
Here it's provided as an Objective-C category (untested):
NSString+SortExtension.h:
#import <Foundation/Foundation.h>
#interface NSString (SortExtension)
- (NSString *)sorted;
#end
NSString+SortExtension.m:
#import "NSString+SortExtension.h"
#implementation NSString (SortExtension)
- (NSString *)sorted
{
// init
NSUInteger length = [self length];
unichar *chars = (unichar *)malloc(sizeof(unichar) * length);
// extract
[self getCharacters:chars range:NSMakeRange(0, length)];
// sort (for western alphabets only)
qsort_b(chars, length, sizeof(unichar), ^(const void *l, const void *r) {
unichar left = *(unichar *)l;
unichar right = *(unichar *)r;
return (int)(left - right);
});
// recreate
NSString *sorted = [NSString stringWithCharacters:chars length:length];
// clean-up
free(chars);
return sorted;
}
#end
I think separate the string to an array of string(each string in the array contains only one char from the original string). Then sort the array will be OK. This is not efficient but is enough when the string is not very long. I've tested the code.
NSString *str = #"stack";
NSMutableArray *charArray = [NSMutableArray arrayWithCapacity:str.length];
for (int i=0; i<str.length; ++i) {
NSString *charStr = [str substringWithRange:NSMakeRange(i, 1)];
[charArray addObject:charStr];
}
NSString *sortedStr = [[charArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] componentsJoinedByString:#""];
// --------- Function To Make an Array from String
NSArray *makeArrayFromString(NSString *my_string) {
NSMutableArray *array = [[NSMutableArray alloc] init];
for (int i = 0; i < my_string.length; i ++) {
[array addObject:[NSString stringWithFormat:#"%c", [my_string characterAtIndex:i]]];
}
return array;
}
// --------- Function To Sort Array
NSArray *sortArrayAlphabetically(NSArray *my_array) {
my_array= [my_array sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
return my_array;
}
// --------- Function Combine Array To Single String
NSString *combineArrayIntoString(NSArray *my_array) {
NSString * combinedString = [[my_array valueForKey:#"description"] componentsJoinedByString:#""];
return combinedString;
}
// Now you can call the functions as in below where string_to_arrange is your string
NSArray *blowUpArray;
blowUpArray = makeArrayFromString(string_to_arrange);
blowUpArray = sortArrayAlphabetically(blowUpArray);
NSString *arrayToString= combineArrayIntoString(blowUpArray);
NSLog(#"arranged string = %#",arrayToString);
Just another example using NSMutableString and sortUsingComparator:
NSMutableString *mutableString = [[NSMutableString alloc] initWithString:#"tomat"];
[mutableString appendString:#"o"];
NSLog(#"Orignal string: %#", mutableString);
NSMutableArray *charArray = [NSMutableArray array];
for (int i = 0; i < mutableString.length; ++i) {
[charArray addObject:[NSNumber numberWithChar:[mutableString characterAtIndex:i]]];
}
[charArray sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
if ([obj1 charValue] < [obj2 charValue]) return NSOrderedAscending;
return NSOrderedDescending;
}];
[mutableString setString:#""];
for (int i = 0; i < charArray.count; ++i) {
[mutableString appendFormat:#"%c", [charArray[i] charValue]];
}
NSLog(#"Sorted string: %#", mutableString);
Output:
Orignal string: tomato
Sorted string: amoott