All elements of nsarray are present in nsstring or not - ios

I want to scan NSString (case insensitive) to check whether all elements of an array contain in that String or not ?
Eg.
NSString *string1 = #"Java is pass by value : lets see how?";
NSString *string2 = #"Java is OOP Language";
NSArray *array = [[NSArray alloc] initWithObjects:#"Java",#"Pass",#"value", nil];
In this case string1 pass the test as it contain all keyword from array (i.e. Java,Pass,Value).
So, how can i achieve this functionality ?

I don't test it for speed, and it will fail on case-sensitive strings, but here's another solution (just in case)
NSArray *components = [string1 componentsSeparatedByString:#" "];
NSSet *textSet = [NSSet setWithArray:components];
NSSet *keywordsSet = [NSSet setWithArray:array];
BOOL result = [keywordsSet isSubsetOfSet:textSet];
Keep in mind that componentsSeparatedByString will tokenize very silly, like "how?" instead of "how" you need.

BOOL containsAll = YES;
for (NSString *test in array) {
if ([string1 rangeOfString:test].location == NSNotFound) {
containsAll = NO;
break;
}
}

Related

How to query an NSDictionary using an expression written in NSString?

I want to be able to run the following hypothetical function called evaluateExpression:on: and get "John" as answer.
NSDictionary *dict = #{"result": #[#{#"name": #"John"}, #{#"name": #"Mary"}]};
NSString *expression = #"response['result'][0]['name']";
NSString *answer = [self evaluateExpression: expression on: dict];
Is this possible?
There's an NSObject category that extends valueForKeyPath to give valueForKeyPathWithIndexes. It lets you write this:
NSDictionary *dict = #{#"result": #[#{#"name": #"John"}, #{#"name": #"Mary"}]};
NSString *path = #"result[0].name";
NSString *answer = [dict valueForKeyPathWithIndexes:path];
XCTAssertEqualStrings(answer, #"John");
The category is by psy, here: Getting array elements with valueForKeyPath
#interface NSObject (ValueForKeyPathWithIndexes)
-(id)valueForKeyPathWithIndexes:(NSString*)fullPath;
#end
#import "NSObject+ValueForKeyPathWithIndexes.h"
#implementation NSObject (ValueForKeyPathWithIndexes)
-(id)valueForKeyPathWithIndexes:(NSString*)fullPath
{
NSRange testrange = [fullPath rangeOfString:#"["];
if (testrange.location == NSNotFound)
return [self valueForKeyPath:fullPath];
NSArray* parts = [fullPath componentsSeparatedByString:#"."];
id currentObj = self;
for (NSString* part in parts)
{
NSRange range1 = [part rangeOfString:#"["];
if (range1.location == NSNotFound)
{
currentObj = [currentObj valueForKey:part];
}
else
{
NSString* arrayKey = [part substringToIndex:range1.location];
int index = [[[part substringToIndex:part.length-1] substringFromIndex:range1.location+1] intValue];
currentObj = [[currentObj valueForKey:arrayKey] objectAtIndex:index];
}
}
return currentObj;
}
#end
Plain old valueForKeyPath will get you close, but not exactly what you asked for. It may be useful in this form though:
NSDictionary *dict = #{#"result": #[#{#"name": #"John"}, #{#"name": #"Mary"}]};
NSString *path = #"result.name";
NSString *answer = [dict valueForKeyPath:path];
XCTAssertEqualObjects(answer, (#[#"John", #"Mary"]));
After spending quite a while trying to tackle this problem in the most efficient way, here's another take I came up with: Use javascript.
The above approach posted by Ewan definitely takes care of the problem, but I had some additional custom features I wanted to add, and objective-c approach became too complex very quickly. I ended up writing eval code in javascript and integrating it into objective-c using JavascriptCore. With that, it becomes as simple as one line of eval() call.

How do you find characters in an NSArray and return YES in Objective-C?

I am trying to find "Worf" inside the array of strings and then returning the BOOL of "YES" if I do find it, but if not, then return a BOOL of "NO".
So far this is what I have but it isn't working.
NSArray *myArray = #[#"Worf", #"son of Mogh", #"slayer of Gowron"];
NSString *myWorfString = #"Worf";
BOOL yesOrNo = NO;
for (NSString *task in myArray) {
if ([task isEqualToString: myWorfString]) {
yesOrNo = YES;
return yesOrNo;
} else {
return yesOrNo;
}
How would I input "return [myArray containsObject:myWolfString];" into my equation?
First of all you shouldn't compare objects with == unless you know what you are doing, since it compares memory addresses (where they are allocated) and not the contents. So two NSString* which points to two different instances which contain the same value are not equal according to ==.
You should use isEqualToString: or isEqualTo:.
In addition NSArray already contains this functionality, you don't need to reinvent the wheel:
NSArray *myArray = #[#"Worf", #"son of Mogh", #"slayer of Gowron"];
BOOL yesOrNo = [myArray containsObject:#"Worf"];
You have a logic error - you return immediately if the first item in the array is not #"Worf". While others have proposed solutions that will work, this one is most like your original code:
NSArray *myArray = #[#"Worf", #"son of Mogh", #"slayer of Gowron"];
NSString *myWorfString = #"Worf";
for (NSString *task in myArray)
if ([task isEqualToString: myWolfString])
return YES;
return NO;
Rather than go through the items one at a time, you can search the array concurrently, with lots of searches happening in parallel.
NSArray *myArray = #[#"Worf", #"son of Mogh", #"slayer of Gowron"];
NSString *myWorfString = #"Worf";
__block BOOL searchStringFound = NO;
[myArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSString *string, NSUInteger idx, BOOL *stop) {
if ([string isEqualToString:myWorfString]) {
searchStringFound = YES;
*stop = YES;
}
}];
What's the advantage of this? It's faster, rather than search the array serially, you are doing it concurrently. Okay, so in this instance with such a small array it's unlikely to make much difference, but for larger arrays it could.
It's also a useful technique to use when looking for objects in collections. Because once you have found the object, you just set the stop parameter to YES to signal that no more enumerations need to be performed.
If you are looking for a substring:
- (BOOL)array:(NSArray *)array containsSubstring:(NSString *)substringToSearchFor
{
for (NSString *string in array) {
if (! [string isKindOfClass:[NSString class]])
continue; // skip objects that are not an NSString
if ([string rangeOfString:substringToSearchFor].location != NSNotFound)
return YES;
}
return NO;
}
Never compare strings with == use isEqualToString: instead.
You can just write:
return [myArray containsObject:myWolfString];
If you need to also check substring, you can use NSPredicate :
NSArray *myArray = #[#"Worf", #"son of Mogh", #"slayer of Gowron"];
NSString *myWolfString = #"Worf";
NSPredicate *pred = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"SELF CONTAINS [c] '%#'",myWolfString]];
NSArray *filteredArray = [myArray filteredArrayUsingPredicate:pred];
if ([filteredArray count])
{
NSLog(#"Index Of Object in main Array : %lu",(unsigned long)[myArray indexOfObject:filteredArray[0]]);
}
There are various ways you can find characters in NSArray and return YES in objective-c:-
1) By using NSPredicate
NSPredicate *pd=[NSPredicate predicateWithFormat:#"self MATCHES[CD] %#",myWorfString];
BOOL yesOrNo=[[NSNumber numberWithUnsignedLong:[[myArray filteredArrayUsingPredicate:pd]count]]boolValue];
2) Second using containsObjectapi
BOOL yesOrNo = [myArray containsObject:myWorfString];
3) Refer #EricS answer
NSArray *myArray = #[#"Worf", #"son of Mogh", #"slayer of Gowron"];
NSString *myWorfString = #"Worf";
BOOL yesOrNo = NO;
for (NSString *task in myArray)
{
if (([task isEqualToString: myWorfString]) || ([task rangeOfString:myWorfString].location != NSNotFound)) {
yesOrNo = YES;
break;
}
}
return yesOrNo;
Above code will return either array will contain as string or substring in array.

How to split NSString and Rejoin it into two NSStrings?

I have a NSString like this one:
NSString* allSeats = #"1_Male,2_Female,3_Female,4_Male";
I want to split the NSString based on the keywords _Male & _Female and then make two separate strings like these:
NSString* maleSeats = #"1,4";
NSString* femaleSeats = #"2,3";
based on the contents of allSeats variable declared above.
How it will be possible to split NSString and then make 2 seperate strings?
You have to do it yourself. There is no "all done" solution. There are a few ways to do it.
Note: I didn't try my code, I just wrote it, it may don't even compile. But the important thing is that you get the whole idea behind it.
One way could be this one:
NSString *maleSufffix = #"_Male";
NSString *femaleSufffix = #"_Female";
NSMutableArray *femaleSeatsArray = [[NSMutableArray alloc] init];
NSMutableArray *maleSeatsArray = [[NSMutableArray alloc] init];
NSArray *array = [allSeats componentsSeparatedByString:#","];
for (NSString *aSeat in array)
{
if ([aSeat hasSuffix:maleSuffix])
{
[maleSeatsArray addObject:[aSeat stringByReplacingOccurencesOfString:maleSuffix withString:#""]];
}
else if ([aSeat hasSuffix:femaleSuffix])
{
[femalSeatsArray addObject:[aSeat stringByReplacingOccurencesOfString:femaleSuffix withString:#""]];
}
else
{
NSLog(#"Unknown: %#", aSeat);
}
}
NSString *maleSeats = [maleSeatsArray componentsJoinedByString:#","];
NSString *femaleSeats = [femaleSeatsArray componentsJoinedByString:#","];
Of course, you could use different methods on array, enumerating it, use a NSMutableString instead of a NSMutableArray (for femaleSeatsArray or maleSeatsArray, and use adequate methods then in the for loop).
I derived an idea from Larme's Clue and it works as :
Make a method as and call it anywhere :
-(void)seperateSeat
{
maleSufffix = #"_Male";
femaleSufffix = #"_Female";
femaleSeatsArray = [[NSMutableArray alloc] init];
maleSeatsArray = [[NSMutableArray alloc] init];
array = [self.selectedPassengerSeat componentsSeparatedByString:#","];
for (aSeat in array)
{
if ([aSeat hasSuffix:maleSufffix])
{
aSeat = [aSeat substringToIndex:[aSeat length]-5];
NSLog(#"%# is value in final seats ::",aSeat );
[maleSeatsArray addObject:aSeat];
}
else if ([aSeat hasSuffix:femaleSufffix])
{
aSeat = [aSeat substringToIndex:[aSeat length]-7];
NSLog(#"%# is value in final seats ::",aSeat );
[femaleSeatsArray addObject:aSeat];
}
}
totalMales = [maleSeatsArray componentsJoinedByString:#","];
totalFemales = [femaleSeatsArray componentsJoinedByString:#","];
NSLog(#"maleSeatsAre::::%#",totalMales);
NSLog(#"maleSeatsAre::::%#",totalFemales);
}

Replace String Between Two Strings

I have a serious problem about indexing in array. I've been working on this for 2 days and couldn't find answer yet.
I want to do that, search specific character in array then replace it with other string. I'm using replaceObjectAtIndex method but my code is doesn't work.
Here is my code;
NSString *commentText = commentTextView.text;
NSUInteger textLength = [commentText length];
NSString *atSign = #"#";
NSMutableArray *commentArray = [[NSMutableArray alloc] init];
[commentArray addObject:commentText];
for (int arrayCounter=1; arrayCounter<=textLength; arrayCounter++)
{
NSRange isRange = [commentText rangeOfString:atSign options:NSCaseInsensitiveSearch];
if(isRange.location != NSNotFound)
{
commentText = [commentText stringByReplacingOccurrencesOfString:commentText withString:atSign];
[_mentionsearch filtrele:_mentionText];
id<textSearchProtocol> delegate;
[delegate closeList:[[self.searchResult valueForKey:#"user_name"] objectAtIndex:indexPath.row]];
}
}
Ok, now i can find "#" sign in the text and i can match it. But this is the source of problem that, i can not replace any string with "#" sign. Here is the last part of code;
-(void)closeList
{
NSArray *arrayWithSign = [commentTextView.text componentsSeparatedByString:#" "];
NSMutableArray *arrayCopy = [arrayWithSign mutableCopy];
[arrayCopy replaceObjectAtIndex:isRange.location withObject:[NSString stringWithFormat:#"#%#",username]];
}
When im logging isRange.location value, it returns correct. But when im try to run, my application is crashing. So, i can not replacing [NSString stringWithFormat:#"#%#",username] parameter. How can i solve this problem?
If I understand correctly you want to change a substring in a string with a new string. In this case, why don't you use directly the stringByReplacingOccurrencesOfString method of NSString:
NSString *stringToBeChanged = #"...";
NSString *stringToBeChangedWith = #"...";
NSString *commentTextNew = [commentText stringByReplacingOccurrencesOfString:stringToBeChanged withString:stringToBeChangedWith];

NSString remove duplicated substrings

How can I remove duplicated substings from string? For ex. I have: aaa,bbb,ttt,bbb,rrr.
And in result I want to have aaa,bbb,ttt,rrr (deleted duplicated bbb). I hope for your help. Thanks.
You can do it like this:
NSMutableSet *seen = [NSMutableSet set];
NSMutableString *buf = [NSMutableString string];
for (NSString *s in [str componentsSeparatedByString:#","]) {
if (![seen containsObject:s]) {
[seen add:s];
[buf appendFormat:#",%#", s];
}
}
NSString *res = [buf length] ? [buf substringFromIndex:1] : #"";
Do it in three steps
1) NSArray *items = [theString componentsSeparatedByString:#","];
2) remove duplicate element from array
NSArray* array = [NSArray arrayWithObjects:#"test1", #"test2", #"test1", #"test2",#"test4", nil];
NSArray* filteredArray = [[NSArray alloc] init];
NSSet *set= [NSOrderedSet orderedSetWithArray:array];
filteredArray = [set allObjects];
3) Concate String from array
NSString *myString = [myArray componentsJoinedByString:#","];
You can use NSMutableDictionary;
In dictionary there are two elements;
1. Key
2. Value
Just set Keys as your array elements;
Special point is that 'Key' can't be duplicate;
Now just get array of Keys by using [dictionary allKeys];
Now, at this stage you have unique values in new array;

Resources