Checking if two loops returns a value - objective-c

I want to check if the two for loops returns a match, if they do nothing happens but if they don't I want a message to be printed out saying something like "A match could not be found". Something like this:
if (loop1 == 0 && loop2 == 0) {
NSLog(#"A match could not be found, please check your spelling");
};
My question is therefore, how can I describe the loops so that I can check the value they give?
Here are the loops:
for (SMADoc *aSearch in docs) {
if ([search isEqualToString:[aSearch leadAuthour]]) {
//Open the file that is represented by UrlToDoc for that specific object
[[NSWorkspace sharedWorkspace] openFile:[aSearch urlToDoc]];
}
}
} else {
//The string starts with a number and should be converted to an int and then the array of the numbers should be searched through
int number = atoi(searchC);
NSNumber *sNumber = [NSNumber numberWithInt:number];
for (SMADoc *nSearch in docs) {
if ([sNumber isEqualToNumber:[nSearch docNumber]]) {
[[NSWorkspace sharedWorkspace] openFile:[nSearch urlToDoc]];
}
}
}
Thanks in advance!

As your custom class is KVC compliant you could perform the check simultaneously with NSPredicate without any loop.
The expression means: if docs contains an object whose docNumber is number or leadAuthour is search, skip the error message
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"docNumber == %i || leadAuthour == %#", number, search];
if [[docs filteredArrayUsingPredicate:predicate] count] == 0 {
NSLog(#"A match could not be found, please check your spelling");
}

I solved it! I started by declaring two ints, one for each loop, and then checked if a match was NOT found for each iteration, i.e:
![search isEqualToString:[aSearch leadAuthour]]
If this was true, the int was increased by one. Then, after the array was iterated through, if the int is equal to the number of objects in the array, I then knew that none of the objects matched and I could print out the "A match could not be found, please check your spelling"-message. This is how it looked like in code:
int i = 0;
int j = 0;
for (SMADoc *aSearch in docs) {
if ([search isEqualToString:[aSearch leadAuthour]]) {
//Open the file that is represented by UrlToDoc for that specific object
[[NSWorkspace sharedWorkspace] openFile:[aSearch urlToDoc]];
}
if(![search isEqualToString:[aSearch leadAuthour]]){
i++;
}
if(i == [docs count]) {
NSLog(#"A match could not be found, please check your spelling");
}
}
} else {
//The string starts with a number and should be converted to an int and then the array of the numbers should be searched through
int number = atoi(searchC);
NSNumber *sNumber = [NSNumber numberWithInt:number];
for (SMADoc *nSearch in docs) {
if ([sNumber isEqualToNumber:[nSearch docNumber]]) {
[[NSWorkspace sharedWorkspace] openFile:[nSearch urlToDoc]];
}
if(![search isEqualToString:[aSearch docNumber]]){
j++;
}
if(j == [docs count]) {
NSLog(#"A match could not be found, please check your spelling");
}
}
I don't know if it's allowed to answer your own question, but my intention with this was to provide an answer for someone who might be asking the same question.

Related

Matching strings, consider some characters are the same

please help me with this problem.
I want to check if the targetString match the keyword or not. Consider some character may different, but should still return true.
Example:
targetString = #"#ß<"
keyword = #"abc", #"∂B(", #"#Aß<"
result: all must return true.
(Matched.targetString and all keyword are the same.)
Consider me have an array, contains list of character set that can be the same:
NSArray *variants = [NSArray arrayWithObjects:#"aA#∂", #"bBß", #"c©C<(", nil]
So that when matching, with this rule, it can match as the example above.
Here is what i've done so far (using recursion):
- (BOOL) test:(NSString*)aString include:(NSString*) keyWord doTrim:(BOOL)doTrim {
// break recursion.
if([aString length] < [keyWord length]) return false;
// First, loop through each keyword's character
for (NSUInteger i = 0; i < [keyWord length]; i++) {
// Get #"aA#∂", #"bBß", #"c©C<(" or only the character itself.
// like, if the keyword's character is A, return the string #"aA#∂".
// If the character is not in the variants set, eg. P, return #"P"
char c = [keyWord characterAtIndex:i];
NSString *rs = [self variantsWithChar:c];
// Check if rs (#"aA#∂" or #"P") contains aString[i] character
if([rs rangeOfString:[NSString stringWithCharacters:[aString characterAtIndex:i] length:1]].location == NSNotFound) {
// If not the same char, remove first char in targetString (aString), recursion to match again.
return [self test:[aString substringFromIndex:1] include:keyWord doTrim:NO];
}
}
// If all match with keyword, return true.
return true;
}
- (NSString *) variantsWithChar:(char) c {
for (NSString *s in self.variants) {
if ([s rangeOfString:[NSString stringWithFormat:#"%c",c]].location != NSNotFound) {
return s;
}
}
return [NSString stringWithFormat:#"%c", c];
}
The main problem is, variantsWithChar: doesn't return the correct string. I don't know which datatype and which function should I use here. Please help.
For thou who know ruby, here's the example in ruby. It work super fine!
require 'test/unit/assertions'
include Test::Unit::Assertions
class String
def matching?(keyword)
length >= keyword.length && (keyword.chars.zip(chars).all? { |cs| variants(cs[0]).include?(cs[1]) } || slice(1, length - 1).matching?(keyword))
end
private
VARIANTS = ["aA#∂", "bBß", "c©C<("]
def variants(c)
VARIANTS.find { |cs| cs.include?(c) } || c
end
end
assert "abc".matching?("#ß<")
PS: The fact is, it's containt a japanese character set that sounds the same (like あア, いイ... for thou who know japanese)
PS 2: Please feel free to edit this Question, since my engrish is sooo bad. I may not tell all my thought.
PS 3: And, maybe some may comment about the performance. Like, search about 10,000 target words, with nearly 100 variants, each variant have at most 4 more same characters.
So first off, ignore comments about ASCII and stop using char. NSString and CFString use unichar
If what you really want to do is transpose hiragana and katakana you can do that with CFStringTransform()
It wraps the ICU libraries included in OS X and iOS.
It makes it very simple.
Search for that function and you will find examples of how to use it.
After a while (a day) working on the code above, I finally get it through. But don't know about the performance. Someone comment and help me improve about performance, please. Thanks.
- (BOOL) test:(NSString*)aString include:(NSString*) keyWord doTrim:(BOOL)doTrim {
// break recursion.
if([aString length] < [keyWord length]) return false;
// First, loop through each keyword's character
for (NSUInteger i = 0; i < [keyWord length]; i++) {
// Get #"aA#∂", #"bBß", #"c©C<(" or only the character itself.
// like, if the keyword's character is A, return the string #"aA#∂".
// If the character is not in the variants set, eg. P, return #"P"
NSString* c = [NSString stringWithFormat:#"%C", [keyWord characterAtIndex:i]];
NSString *rs = [self variantsWithChar:c];
NSString *theTargetChar = [NSString stringWithFormat:#"%C", [aString characterAtIndex:i]];
// Check if rs (#"aA#∂" or #"P") contains aString[i] character
if([rs rangeOfString:theTargetChar].location == NSNotFound) {
// If not the same char, remove first char in targetString (aString), recursion to match again.
return [self test:[aString substringFromIndex:1] include:keyWord doTrim:NO];
}
}
// If all match with keyword, return true.
return true;
}
If you remove all comment, it'll be pretty short...
////////////////////////////////////////
- (NSString *) variantsWithChar:(NSString *) c{
for (NSString *s in self.variants) {
if ([s rangeOfString:c].location != NSNotFound) {
return s;
}
}
return c;
}
You could try comparing ascii values of the japanese characters in the variants's each character's ascii value. These japanese characters aren't treated like usual characters or string. Hence, string functions like rangeOfString won't work on them.
to be more precise: have a look at the following code.
it will search for "∂" in the string "aA#∂"
NSString *string = #"aA#∂";
NSMutableSet *listOfAsciiValuesOfString = [self getListOfAsciiValuesForString:string]; //method definition given below
NSString *charToSearch = #"∂";
NSNumber *ascii = [NSNumber numberWithInt:[charToSearch characterAtIndex:0]];
int countBeforeAdding = [listOfAsciiValuesOfString count],countAfterAdding = 0;
[listOfAsciiValuesOfString addObject:ascii];
countAfterAdding = [listOfAsciiValuesOfString count];
if(countAfterAdding == countBeforeAdding){ //element found
NSLog(#"element exists"); //return string
}else{
NSLog(#"Doesnt exists"); //return char
}
===================================
-(NSMutableSet*)getListOfAsciiValuesForString:(NSString*)string{
NSMutableSet *set = [[NSMutableSet alloc] init];
for(int i=0;i<[string length];i++){
NSNumber *ascii = [NSNumber numberWithInt:[string characterAtIndex:i]];
[set addObject:ascii];
}
return set;
}

Efficient way of checking the content of every NSDictionary in NSArray

In my app I'me getting responses from the server and I have to check that I don't create duplicate objects in the NSArray which contains NSDictionaries. Now to check if the objects exists I do this:
for (int i = 0; i < appDelegate.currentUser.userSiteDetailsArray.count; i++){
NSDictionary *tmpDictionary = [appDelegate.currentUser.userSiteDetailsArray objectAtIndex:i];
if ([[tmpDictionary valueForKey:#"webpropID"] isEqualToString:tmpWebproperty.identifier]){
needToCheck = NO;
}
if (i == appDelegate.currentUser.userSiteDetailsArray.count - 1 && ![[tmpDictionary valueForKey:#"webpropID"] isEqualToString:tmpWebproperty.identifier] && needToCheck){
// It means it's the last object we've iterated through and needToCheck is still = YES;
//Doing stuff here
}
}
I set up a BOOL value because this iteration goes numerous times inside a method and I can't use return to stop it. I think there is a better way to perform this check and I would like to hear your suggestions about it.
BOOL needToCheck = YES;
for (int i = 0; i < appDelegate.currentUser.userSiteDetailsArray.count; i++){
NSDictionary *tmpDictionary = [appDelegate.currentUser.userSiteDetailsArray objectAtIndex:i];
if ([[tmpDictionary valueForKey:#"webpropID"] isEqualToString:tmpWebproperty.identifier]){
needToCheck = NO;
break;
}
}
if (needToCheck) {
//Doing stuff here
}
But, as others have said, you can maybe keep a "summary" in a separate NSSet that you check first, vs spinning through all the dictionaries.
NSDictionary *previousThing = nil;
for (NSDictionary *thing in appDelegate.currentUser.userSiteDetailsArray) {
if ([thing[#"webpropID"] isEqualToString:newWebPropertyIdentifier]) {
previousThing = thing;
break;
}
}
if (previousThing == nil) {
// no previous thing
} else {
// duplicate
}

Search String in NSDictionary store in NSMutableArray

I am trying to search a String in NSDictionary stored in NSMutableArray
for (int k = 0; k < [onlyActiveArr count]; k++) {
NSString *localID = [onlyActiveArr objectAtIndex:k];
NSLog(#"%#",localID);
int localIndex = [onlyActiveArr indexOfObject:localActiveCallID];
NSLog(#"%d",localIndex);
for (NSDictionary *dict in self.SummaryArr) {
NSLog(#"%#",[dict objectForKey:#"ActiveID"]);
if (![[dict objectForKey:#"ActiveID"] isEqualToString:localID]) {
NSLog(#"found such a key, e.g. %#",localID);
}
}
}
But I am getting
NSLog(#"found such a key, e.g. %#",localActiveCallID);
when the ID is still there in SummaryArr, I am checking if localID retrieved from onlyActiveArr is not present in dictionary.
Please suggest me how to overcome my problem.
You cannot make a decision that a key is not present until you finish processing the entire dictionary. Make a boolean variable initially set to NO, and change it to YES if you find an item in the dictionary, like this:
BOOL found = NO;
for (NSDictionary *dict in self.SummaryArr) {
NSLog(#"%#",[dict objectForKey:#"ActiveID"]);
found = [[dict objectForKey:#"ActiveID"] isEqualToString:localID];
if (found) break;
}
if (!found) {
NSLog(#"found such a key, e.g. %#",localID);
}
If you like predicates, then you can use the fact that accessing an inexistent key in a dictionary produces a nil value and make a predicate that filters out those dictionaries that have nil for your key.
If the count of the result is larger than zero, your key is somewhere in the array. It won't tell you where, though.
A snippet to show the idea:
NSPredicate *keyPred = [NSPredicate predicateWithFormat: #"NOT ActiveID == nil"];
BOOL found = [[self.SummaryArr filteredArrayUsingPredicate: keyPred] count] > 0;
I don't know how the performance stacks up, so if your data set is large you may want to check that the execution time is within your limits.

Copying an object from one NSMutable array to another

I have done a bit of searching and not really found an answer to my question.
The code below is trying to copy the contents of a NSMutable array that contains some objects.
I have tried the code below however when run there is no error, but the new arrays do not get the objects as I would have thought they would.
csvContent is a array that contains objects from parsing a CSV file and the other NSMutable arrays round1, round2 etc have been defined in the header file.
The NSLOG output is correct but the arrays contain no objects.
for(int loopNumber = 0; loopNumber < [csvContent count]; loopNumber++)
{
if ([[[csvContent objectAtIndex:loopNumber] objectAtIndex:1] isEqualToString:#"1"])
{
[round1 addObject:[csvContent objectAtIndex:loopNumber]];
NSLog(#"round 1");
}
if ([[[csvContent objectAtIndex:loopNumber] objectAtIndex:1] isEqualToString:#"2"])
{
[round2 addObject:[csvContent objectAtIndex:loopNumber]];
NSLog(#"round 2");
}
if ([[[csvContent objectAtIndex:loopNumber] objectAtIndex:1] isEqualToString:#"3"])
{
[round3 addObject:[csvContent objectAtIndex:loopNumber]];
NSLog(#"round 3");
}
}
Did you actually create and initialize the arrays for round1, round2, and round3? In other words, make sure they are not nil when this loop is run.
Also, your code is terribly inefficient. You call [csvContent objectAtIndex:loopNumber] six times inside the loop. Try this (I'm using i instead of loopNumber to save typing):
for (int i = 0; i < csvContent.count; i++) {
NSArray *loopContent = csvContent[i];
NSString *val = loopContent[1];
if ([val isEqualToString:#"1"]) {
[round1 addObject:loopObject];
} else if ([val isEqualToString:#"2"]) {
[round2 addObject:loopObject];
} else if ([val isEqualToString:#"3"]) {
[round3 addObject:loopObject];
}
}

Objective-C, get string from text file?

I know there are a few different ways to find text in file, although I haven't found a way to return the text after the string I'm searching for. For example, if I was to search file.txt for the term foo and wanted to return bar, how would I do that without knowing it's bar or the length?
Here's the code I'm using:
if (!fileContentsString) {
NSLog(#"Error reading file");
}
// Create the string to search for
NSString *search = #"foo";
// Search the file contents for the given string, put the results into an NSRange structure
NSRange result = [fileContentsString rangeOfString:search];
// -rangeOfString returns the location of the string NSRange.location or NSNotFound.
if (result.location == NSNotFound) {
// foo not found. Bail.
NSLog(#"foo not found in file");
return;
}
// Continue processing
NSLog(#"foo found in file");
}
you could use [NSString substringFromIndex:]
if (result.location == NSNotFound)
{
// foo not found. Bail.
NSLog(#"foo not found in file");
return;
}
else
{
int startingPosition = result.location + result.length;
NSString* foo = [fileContentsString substringFromIndex:startingPosition]
NSLog(#"found foo = %#",foo);
}
You might want to use RegexKitLite and perform a regex look up:
NSArray * captures = [myFileString componentsMatchedByRegex:#"foo\\s+(\\w+)"];
NSString * wordAfterFoo = captures[1];
Not test though.