Get index of object in array to look up corresponding object in other array - iphone

I have two arrays. One is an array of names and the other is an array made up of strings titled "Yes" or "No". The index path of each name in the "name" array corresponds with the same index path in the "Yes/No" array. For example:
Names Array | Yes/No Array
Person 1 | Yes
Person 2 | No
Person 3 | Yes
What would be the easiest way to look up a person's name (possibly getting the index path of it) and check whether they are "Yes" or "No" in the "Yes/No" array?
Also, I'm not sure if "index path" is the right term to use. If it isn't, I mean the number that an object is in an array.

NSArray has a method called indexOfObject that will return either the lowest index whose corresponding array value is equal to anObject or NSNotFound if no such object is found. If your array of names is unsorted, then use this to get the index that you can then plug in to the Yes/No array. That is, something along these lines:
NSString *answer = nil;
NSUInteger index = [namesArray indexOfObject:#"John Smith"];
if (index != NSNotFound) {
answer = [yesNoArray objectAtIndex:index];
}
return answer;
Because Bavarious asks questions where I assume, here's a better way when the array of names is sorted alphabetically.
int index = [self findName:#"John Smith"];
NSString *answer = nil;
if (index >= 0) {
answer = [yesNoArray objectAtIndex:index];
}
return answer;
where the function findName is a simple binary search:
-(int)findName:(NSString *)name {
int min, mid, max;
NSComparisonResult comparisonResult;
min = 0;
max = [namesArray count]-1;
while (min <= max) {
mid = min + (max-min)/2;
comparisonResult = [name compare:[namesArray objectAtIndex:mid]];
if (comparisonResult == NSOrderedSame) {
return mid;
} else if (comparisonResult == NSOrderedDescending) {
min = mid+1;
} else {
max = mid-1;
}
}
return -1;
}

Trying to keep two arrays synchronized is just asking for trouble. It can be done, of course, but whenever you modify one array, you have to remember to make a corresponding change to the other. Do yourself a favor and avoid that entire class of bugs by rethinking the way you're storing data.
In this case, you've got a {person, boolean} pair. One option is to store each pair as a dictionary, and then keep an array of those dictionaries. This would be a particularly good plan if you might expand the number of pieces of data beyond the two that you have. Another option would be to just use a dictionary where keys are person names and the values are your yes/no values. This makes the answer to your question very simple:
NSString *yesOrNo = [personDictionary objectForKey:personName];
Getting back to your original question, where you still have the two arrays, the easiest thing to do is to iterate over the person array until you find the person you're looking for, get the index of that name, and then look up the corresponding value in the yes/no array:
for (person in peopleArray) {
if ([person isEqualToString:thePersonYoureLookingFor]) {
yesNoValue = [yesNoArray objectAtIndex:[peopleArray indexOfObject:person];
break;
}
}
That's fine if the number of people in the list isn't too large. If the list could be large, then you'll want to keep the person array sorted so that you can do a binary search. The trouble there, though, is that you're yes/no array is separate, so sorting the personArray while keeping the yes/no array in the right order becomes complicated.

You can also use below of the code, May its useful to you,
NSSortDescriptor *_lastDescriptor = [[NSSortDescriptor alloc] initWithKey:#"" ascending:YES];
NSArray *_lastArray = [NSArray arrayWithObject:_lastDescriptor];
firstCharacterArray = (NSMutableArray *)[[nameIndexesDictionary allKeys]
sortedArrayUsingDescriptors:_lastArray];
//firstCharacterArray = (NSMutableArray *)[[nameIndexesDictionary allKeys]
sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
for (NSString *eachlastIndex in firstCharacterArray)
{
NSSortDescriptor *lastDescriptor = [[NSSortDescriptor alloc] initWithKey:#""
ascending:YES];
//selector:#selector(localizedCaseInsensitiveCompare:)] ;
NSArray *descriptorslast = [NSArray arrayWithObject:lastDescriptor];
[[nameIndexesDictionary objectForKey:eachlastIndex]
sortUsingDescriptors:descriptorslast];
[lastDescriptor release];
}

You can use indexOfObject method to get the index of element.
for example
This will give you index of your object
NSInteger index = [yourArray indexOfObject:objectName];
To see the corresponding element from another array
[anotherArray objectAtIndex:index];
This worked for me. Hope this helps.

Related

Filter specific values from array of string

I have an array of following values
["130896-220","130897-901","130011-990","130012-991"]
and I am filter out of only those values which contain 900 to 999 at end of value.
I need following result of array ["130897-901","130011-990","130012-991"].
Simply call filter(_:) on arr with the relevant condition to filter the elements within the range 900...999
let arr = ["130896-220","130897-901","130011-990","130012-991"]
let range = (900...999)
let result = arr.filter({
if let str = $0.components(separatedBy: "-").last, let num = Int(str) {
return range.contains(num)
}
return false
})
print(result) //["130897-901", "130011-990", "130012-991"]
An alternative is Regular Expression
let array = ["130896-220","130897-901","130011-990","130012-991"]
let filteredArray = array.filter{$0.range(of: "^\\d{6}-9\\d{2}$", options: .regularExpression) != nil}
The pattern "^\\d{6}-9\\d{2}$" searches for
six digits followed by
one hyphen followed by
9 followed by
two other digits
A little bit unconventional Objective-C solution:
NSArray *data = #[#"130896-220", #"130896-901", #"130896-903"];
// We'll fill this array with the final filtered result
NSMutableArray* filteredData = [[NSMutableArray alloc] init];
for (NSString* str in data) { // Iterate between strings
int value = [[str componentsSeparatedByString:#"-"][1] intValue];
if(value > 900 && value < 1000){
[filteredData addObject:str];
}
}
Edit:
Inside the for I use the method componentsSeparatedByString:#"" this will return an array with strings separated by the entered value. In this case we know that we want the value after the "-" character so we access the second index of the array directly ([1]).
Lastly, we check if the value is compressed between the values we want. If so, is added to the filtered array.

How to match the id's to names iphone?

I am getting Names and ID's from DB... and storing those values in Array... Like Names storing in NamesArray and ID's storing in IDsArray...
Example:
NamesArray - {Peter, Arnold, John,Samuel}
IDsArray - {1, 2, 3,4}
After getting those values from DB... I am sorting NamesArray... It will come like this...
NamesArray Value - {Arnold,John,Peter,Samuel}
How to change the IDsArray according to the NamesArray?
The same scenario is needed for Search functionality....
Example:
I am searching 'P' text in SearchBar... It will show 'Peter' in TableView...
How to get the IDs from idarray according to the Searched Text?
Thanks in advance
You could use an array of dictionaries with keys Name and ID. After you could use NSPredicate for your search and NSSortDescriptor for sorting
yourArray: (
{
id = 1;
name = Peter;
},
{
id = 2;
name = Arnold;
},
{
id = 3;
name = John;
},
{
id = 4;
name = Samuel;
});
Sort
nameDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
nameDescriptors = [NSArray arrayWithObject:nameDescriptor];
sortedArray = [yourArray sortedArrayUsingDescriptors:nameDescriptors];
Filter
NSString *strToFilter = #"P";
NSArray *filteredNames = [yourArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"(name BEGINSWITH[c] %#)", strToFilter]];
For this scenario simple logic can be done.
NamesArray - {Peter, Arnold, John,Samuel}
IDsArray - {1, 2, 3,4}
Have the searched names in separate array which will not affect NamesArray when you search.
searchedNamesArray - {Peter}
after that get the index of the searched object from array
for (NSString *value in searchedNamesArray)
{
NSInteger index = [NamesArray indexOfObject:value];
// you will get the index of the object from which you can use from getting the id from IDsArray
NSLog(#"ID - %#", [IDsArray objectAtIndex:index]);
}

How to Compare Two NSStrings which contain float values? [duplicate]

This question already has answers here:
Compare version numbers in Objective-C
(15 answers)
Closed 9 years ago.
I have two strings, one contains the value "5.2.3" and another one contain a value like "5.2.32". My question is: how to compare these two strings?
if ([string1 integerValue] >= [sting2 integerValue])
{
NSLog(#"process");
}
I tried above line but not got it.
Well correct answer has been already given. Because I have spent my half an hour on it so I don't want to waste it.
-(BOOL)string:(NSString*)str1 isGreaterThanString:(NSString*)str2
{
NSArray *a1 = [str1 componentsSeparatedByString:#"."];
NSArray *a2 = [str2 componentsSeparatedByString:#"."];
NSInteger totalCount = ([a1 count] < [a2 count]) ? [a1 count] : [a2 count];
NSInteger checkCount = 0;
while (checkCount < totalCount)
{
if([a1[checkCount] integerValue] < [a2[checkCount] integerValue])
{
return NO;
}
else if([a1[checkCount] integerValue] > [a2[checkCount] integerValue])
{
return YES;
}
else
{
checkCount++;
}
}
return NO;
}
And you can call this method like this:-
if([self string:str1 isGreaterThanString:str2])
{
NSLog(#"str2 is lower than the str1");
}
else
{
NSLog(#"str1 is lower than the str2");
}
It would appear that what you have here are not really "float" values, but some kind of multi-part "number" (akin to software version numbering?) that is not going to be covered by any of the standard conversions, but will also not compare "correctly" as just simple strings.
First you need to specify exactly what your comparison rules are. For example, I suspect you want something like:
1.2 > 1.1
1.1.1 > 1.1
1.11 > 1.2
1.2.3 > 1.2.2
1.2.22 > 1.2.3
(in other words, split the string up by "."s, and do a numeric comparison on each component). You'll have to decide how you want to handle things like letters, other delimiters, etc. showing up in the input. For example is 1.0b1 > 1.01 ?
Once you settle on the rules, write a method (returning NSComparisonResult) to implement the comparison. If you want to get fancy, you can even define your comparison method in a category on NSString, so you could do things like
if ([string1 mySuperDuperCompareTo:string2] == NSOrderedAscending) {
NSLog(#"%# < %#", string1, string2);
} // ... etc ...
see also How to let the sortedArrayUsingSelector using integer to sort instead of String?
#The Tiger is correct. Sorry to misunderstood your question. I have already mark deleted as my older answer. Here is the updated one.
As there are multiple . (dots) available here is the new solution. This will check value first like 5.2.3 and 5.2.32 are there. Then,
check first value 5 - same
so check next 2 - same
check next 3 and 32 - 32 is larger
also check for the same string as well (Also one of the probability)
Here is the logic - I have not compiled but this is base idea - there might require some correction
// separate from "."
NSArray *arrString1 = [string1 componentSeparatedBy:#"."];
NSArray *arrString2 = [string1 componentSeparatedBy:#"."];
BOOL isString1Bigger = NO; // a variable to check
BOOL isString2Bigger = NO; // a variable to check
// check count to run loop accordingly
if ([arrString1 count] <= [arrString2 count]) {
for (int strVal=0; strVal<[arrString1 count]; strVal++) {
// compare strings value converted into integer format
// when you get larger then break the loop
if([[arrString1 objectAtIndex:strVal] intValue] > [[arrString2 objectAtIndex:strVal] intValue]) {
isString1Bigger = YES;
break;
}
}
if ([arrString1 count] > [arrString2 count]) {
// use arrString2 in loop and isString2Bigger as a mark
}
// if after running both the if condition still require to check if both are same or not, for that,
if ((isString1Bigger == NO) && (isString2Bigger == NO)) {
// same string values
}
There might some modification required to run over. But its the base concept to compare string value provided by you.

how to solve a conditional equation in iOS

I want to solve a conditional equation in iOS:
The equation I get from database is in NSString format, for example:
if((height > 0), (weight+ 2 ), ( weight-1 ) )
As per our understanding, if I parse the above string and separateheight>0condition, it will be in the NSString format. But to evaluate it how do I convert the string to a conditional statement?
Once the conditional statement is obtained the equation can be solved by converting it to a ternary equation as follows:
Bool status;
NSString *condition=#” height>0”;
If(condition)    //But condition is treated as a string and not as a conditional statement.
{
status=True;
}
else
{
status=False;
}
Return status ? weight+ 2 : weight-1;`
Also the equations can dynamically change, so they cannot be hard coded. In short how do I solve this equation which I get as a NSString.
Thank you for your patience!
DDMathParser author here...
To expand on Jonathan's answer, here's how you could do it entirely in DDMathParser. However, to parse the string as-is, you'll need to do two things.
First, you'll need to create an if function:
DDMathEvaluator *evaluator = [DDMathEvaluator sharedMathEvaluator];
[evaluator registerFunction:^DDExpression *(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError *__autoreleasing *error) {
if ([args count] == 3) {
DDExpression *condition = [args objectAtIndex:0];
DDExpression *resultExpression = nil;
NSNumber *conditionValue = [condition evaluateWithSubstitutions:vars evaluator:eval error:error];
if ([conditionValue boolValue] == YES) {
resultExpression = [args objectAtIndex:1];
} else {
resultExpression = [args objectAtIndex:2];
}
NSNumber *result = [resultExpression evaluateWithSubstitutions:vars evaluator:eval error:error];
return [DDExpression numberExpressionWithNumber:result];
}
return nil;
} forName:#"if"];
This creates the if() function, which takes three parameters. Depending on how the first parameter evaluates, it either evaluates to the result of the second or third parameter.
The other thing you'll need to do is tell the evaluator what height and weight mean. Since they don't start with a $ character, they get interpreted as functions, and not variables. If they started with a $, then it would be as simple as evaluating it like this:
NSString *expression = #"if(($height > 0), ($weight+ 2 ), ( $weight-1 ) )";
NSDictionary *variables = #{#"height" : #42, #"weight" : #13};
NSNumber *result = [expression evaluateWithSubstitutions:variables evaluator:evaluator error:nil];
However, since they don't start with a $, they're functions, which means you need to tell the evaluator what the functions evaluate to. You could do this by creating functions for both height and weight, just like you did for if:
[evaluator registerFunction:^DDExpression *(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError **error) {
return [DDExpression numberExpressionWithNumber:#42];
} forName:#"height"];
Alternatively, you could make it a bit more dynamic and use the functionResolver block of DDMathEvaluator, which is a block that returns a block (woooooo) and would look like this:
NSDictionary *values = #{#"height": #42, #"weight": #13};
[evaluator setFunctionResolver:^DDMathFunction(NSString *name) {
DDMathFunction f = ^(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError **error) {
NSNumber *n = [values objectForKey:name];
if (!n) { n = #0; }
return [DDExpression numberExpressionWithNumber:n];
};
return f;
}];
With those two pieces in place (registering if and providing the values of height and weight), you can do:
NSString *expression = #"if((height > 0), (weight+ 2 ), ( weight-1 ) )";
NSNumber *result = [expression evaluateWithSubstitutions:nil evaluator:evaluator error:nil];
... and get back the proper result of #15.
(I have plans to make DDMathParser allow unknown functions to fall back to provided variable values, but I haven't quite finished it yet)
you will have to write your own interpreter or find one that supports this kind of expressions.
The first part (the condition) can be evaluated by NSPredicate. For the second part (the calculation) you will need some math expression evaluation. Try this out https://github.com/davedelong/DDMathParser. Maybe you can do both with DDMathParser but i am not sure.

How to access a certain value in an NSArray?

I have an array called someArray. I would like to access the name value of the NSArray. I'm trying to access it using the following, but with out any luck. How do I do it properly?
cell.textLabel.text = [[someArray objectAtIndex:indexPath.row] objectForKey:#"name"];
some array {
haserror = 0;
headers = {
code = 0;
haserror = 0;
nodeid = "fe1.aaaaaa.2.undefined";
time = 16;
};
results = (
{
coords = (
"44.916667",
"8.616667"
);
id = 2;
key = alessandria;
name = Alessandria;
state = Piemonte;
zip = 1512;
},
{
coords = (
"43.616944",
"13.516667"
);
id = 3;
key = ancona;
name = Ancona;
state = Marche;
zip = 601;
},
}
As far as i see from you data model, the key name is a node under the key results. You can use this data model as a dictionary map, the code snippet below must give you what you need..
NSDictionary *myObject = [[someArray objectAtIndex:indexPath.row] objectForKey:#"results"];
cell.textLabel.text = [myObject objectForKey:"name"];
IMPORTANT NOTE: If you have some lopps or some other mechanisms for receiving data, there may be more efficent ways for your sıolution, so please give some more additional info about what you are exactly tryin to do
As others have noted, someArray is a dictionary while results is a key pointing to an array inside of your dictionary. If you want an array of all of the name fields in your results array, you could use valueForKeyPath: on the someArray variable, like this:
NSArray *names = [someArray valueForKeyPath:#"results.name"];
The names variable should now contain "Alessandria", and "Ancona" from the data set your show in your example code.