I have a list of variables that are named based on two digits then a word i.e. val11 or val26
I need to perform a check on whether a certain value for a variable is equal to the next variable i.e. that val32 == val33
I have the names of the first variables that I need to check in an NSArray (i.e val33)
I can then write a function to perform the check as a lot of long winded if statements
-(void)checkValues:(NSArray *)valueArray {
for (int x = 0; x < [valueArray count]; x++) {
tempStr = [offFiles objectAtIndex:x];
//split variable name
NSString *value = [tempStr substringWithRange:NSMakeRange(3,2];
int numValue= [value intValue];
//long winded if statement
if (numValue == 11) {
if(val11 == val12) {
//do something
}
}
if (numValue == 12) {
if(val12 == val13) {
//do something
}
}
.... etc
if (numValue == 87) {
if(val87 == val88) {
//do something
}
}
}
}
Is there any way I can remove the long winded if statement and replace it with a reference to the next variable so that no matter what variable name is in the array I can easily just check it against the next variable
Something like the excel command indirect
=INDIRECT(CONCATENATE("Cell!A",numValue + 1))
Unless there is some need for you to store your data in a set of discrete separate variables, this is clearly a situation were an array would work for you. This could be either a c-style array or one using NSArray - its up to you.
Using a c-style array (assuming 10 completely made up values):
int myValues[10] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }
Then your series of if statements can be reduced to one:
if (myValues[numValue] == myValues[numValue+1]) {
// so something
}
So if numValue is 3, it would compare myValues[3] and myValues[4] - essentially the same as comparing val3 and val4 in your scheme. Please note that arrays are zero based - the first value is accessed myValue[0] - so if your numbering scheme is 1-based then you need to subtract 1, e.g.:
if (myValues[numValue-1] == myValues[numValue]) {
// do something
}
Beside from the syntax bugs (like starting variable names with a number), what you are looking for is the switch() statement:
switch(a)
{
case 1: // if a is 1 do the following
printf("a is 1");
break;
case 2: // if a is 2
printf("a is 2");
break;
....
default: // if a was none of the cases before do this
printf("a sucks!!");
}
Notice that you always need a break; statement at the end of each case x:
Related
Within a loop, it is possible to do something every other time by using odd and even and testing for even. I would like to do something a fixed number of times eg four no matter how many iterations there are in the loop (value of i). Is there a way to do something every nth time?
I think there must be a way by incrementing a second counter, but having trouble getting it.
A Loop
int i = 0;
int movinglimit = 0;
int incr = [myItems count]/4;;// there might be 10, 20 or 30 items. I only want to do something four times
while (i < [myItems count]) {
if ((i % 2) == 0) {
//do something if even
}
if (i>movinglimit) {
//do something a total of four times
}
if (i==moving limit+1) {
movinglimit = movinglimit + incr;
}
i++;
}
Assuming myItems is an NSArray or NSMutableArray or NSSet you can apply methods on all objects at once which is smarter than implementing an iteration looping thru object by object yourself. That way you take full advantage of objC.
[myItems makeObjectsPerformSelector:#selector(yourObjectMethodToApply)];
This has the side effect that nothing is done/applied if myItems is nil
A short comment on your pseudocode.
Be careful with while loops without any increment inside.
The one you show here is only looping once.
//iteration backward
NSUInteger i = myItems.count-1;
for ( ; i>0; ) {
if ((i % 2) == 0) {
// do stuff if 4th is even
}
// do stuff on every 4th one
i-=4; //increment does not have to be in for () declaration
}
identify the similarity (also backward iteration) to
NSUInteger i = myItems.count-1;
while (i>0) {
// do stuff on each 4th item
//check for odd/even
myItems[i] = i % 2 ? /* even stuff */ : /* odd stuff */;
i-=4; //decrement i
}
You tagged Swift so I assume you want Ob-C or Swift answers. You can enumerate the loop and use that enumeration (which I call n below). The first enumeration will always be 0, of course, so to simplify the even/odd parity, just add 1 to make the first iteration 1.
let data = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
for (n, i) in data.enumerated() {
if (n+1).isMultiple(of: 2) {
print(n+1, i) // every even iteration
}
}
// output: 2 b, 4 d, 6 f, 8 h, 10 j
for (n, i) in data.enumerated() {
if (n+1) <= (4*2), (n+1).isMultiple(of: 2) {
print(n+1, i) // every even iteration but only 4 times
}
}
// output: 2 b, 4 d, 6 f, 8 h
Hi there I have some code at the moment that gives me the error ("0") is not equal to ("50") - condition not applied correctly Basically I am currently using a traditional for loop within a BOOL which goes through the list of items and checks whether or not the condition can be applied, if it can be applied to an item then the BOOL will return YES. I cannot see where I am currently going wrong and need guidance. My code is shown below:
-(BOOL)conditionCanBeApplied:(NSArray *)items{
bool itemConditionCanBeApplied = NO;
for (int i = 0; i < items.count; i++)
{
id myItem = [[items valueForKeyPath:#"itemId"]objectAtIndex: i];
if ([self.applicableItems containsObject:myItem]) {
itemConditionCanBeApplied = YES;
}
}
return itemConditionCanBeApplied;
}
First, don't mix BOOL and bool, they might be very similar but they aren't the same data type. Second, always use fast enumeration if you have a choice. I am assuming in the code below that your items collection is something like an NSArray. Also, there is no reason to test with an if statement just to set a BOOL since the test is a boolean statement. (I am doing it in my example to allow for the break) Lastly, short-circuiting your logic with a break keeps the processor from doing unnecessary work once you have at least one match.
Do something like this:
- (BOOL)conditionTest
{
BOOL itemConditionCanBeApplied = NO;
for (id item in items) {
if ([self.applicableItems containsObject:item]) {
itemConditionCanBeApplied = YES;
break;
}
}
return itemConditionCanBeApplied;
}
I'm using a for-loop to determine whether the long double is an int. I have it set up that the for loop loops another long double that is between 2 and final^1/2. Final is a loop I have set up that is basically 2 to the power of 2-10 minus 1. I am then checking if final is an integer. My question is how can I get only the final values that are integers?
My explanation may have been a bit confusing so here is my entire loop code. BTW I am using long doubles because I plan on increasing these numbers very largely.
for (long double ld = 1; ld<10; ld++) {
long double final = powl(2, ld) - 1;
//Would return e.g. 1, 3, 7, 15, 31, 63...etc.
for (long double pD = 2; pD <= powl(final, 0.5); pD++) {
//Create new long double
long double newFinal = final / pD;
//Check if new long double is int
long int intPart = (long int)newFinal;
long double newLong = newFinal - intPart;
if (newLong == 0) {
NSLog(#"Integer");
//Return only the final ints?
}
}
}
Just cast it to an int and subtract it from itself?
long double d;
//assign a value to d
int i = (int)d;
if((double)(d - i) == 0) {
//d has no fractional part
}
As a note... because of the way floating point math works in programming, this == check isn't necessarily the best thing to do. Better would be to decide on a certain level of tolerance, and check whether d was within that tolerance.
For example:
if(fabs((double)(d - i)) < 0.000001) {
//d's fractional part is close enough to 0 for your purposes
}
You can also use long long int and long double to accomplish the same thing. Just be sure you're using the right absolute value function for whatever type you're using:
fabsf(float)
fabs(double)
fabsl(long double)
EDIT... Based on clarification of the actual problem... it seems you're just trying to figure out how to return a collection from a method.
-(NSMutableArray*)yourMethodName {
NSMutableArray *retnArr = [NSMutableArray array];
for(/*some loop logic*/) {
// logic to determine if the number is an int
if(/*number is an int*/) {
[retnArr addObject:[NSNumber numberWithInt:/*current number*/]];
}
}
return retnArr;
}
Stick your logic into this method. Once you've found a number you want to return, stick it into the array using the [retnArr addObject:[NSNumber numberWithInt:]]; method I put up there.
Once you've returned the array, access the numbers like this:
[[arrReturnedFromMethod objectAtIndex:someIndex] intValue];
Optionally, you might want to throw them into the NSNumber object as different types.
You can also use:
[NSNumber numberWithDouble:]
[NSNumber numberWithLongLong:]
And there are matching getters (doubleValue,longLongValue) to extract the number. There are lots of other methods for NSNumber, but these seem the most likely you'd want to be using.
Wondering if there is a way to shorthand these conditionals. I am working with data packets and the conditionals get a bit unwieldy at times. Here's a basic example:
I write:
if (message->messageType != kMessageTypeCutCardsArray && message->messageType != kMessageTypeQuit) {
MessageInt message;
message.message.messageType = kMessageTypeReceivedData;
NSData *packet = [NSData dataWithBytes:&message length:sizeof(message)];
[_game sendData:packet];
}
I would rather write:
if (message->messageType != (kMessageTypeCutCardsArray || kMessageTypeQuit)) {
MessageInt message;
message.message.messageType = kMessageTypeReceivedData;
NSData *packet = [NSData dataWithBytes:&message length:sizeof(message)];
[_game sendData:packet];
}
As a general matter, no. That's just the way that C (and hence Objective-C) works.
In this specific case, you could use a switch statement:
switch (message->messageType)
{
case kMessageTypeCutCardsArray:
case kMessageTypeQuit:
break;
default:
MessageInt message;
message.message.messageType = kMessageTypeReceivedData;
NSData *packet = [NSData dataWithBytes:&message length:sizeof(message)];
[_game sendData:packet];
break;
}
Whether that syntax is an improvement is up to you.
If you define your enum such that the values have mutually-exclusive bit patterns, like so:
typedef enum : NSUInteger {
kMessageTypeLoveLetter = 1 << 0,
kMessageTypeBirthdayCard = 1 << 1,
kMessageTypeVacationPostcard = 1 << 2,
kMessageTypeCreditApplication = 1 << 3,
kMessageTypeCharitySolicitation = 1 << 4
} MessageType;
You can then test for multiple values at once, using binary OR | and binary AND &:
MessageType msgType = kMessageTypeCreditApplication;
if( !(msgType & (kMessageTypeLoveLetter | kMessageTypeBirthdayCard)) ){
// Nobody loves you.
}
if( (msgType & (kMessageTypeCreditApplication | kMessageTypeCharitySolicitation) ){
// Someone wants your money.
}
This won't work, however, if you use the compiler-generated consecutive values for the enum, because the values will overlap as flags -- e.g., both 2 and 3 have the lowest bit set -- and ORing them together will often end up testing only one of the flags.
You could box the values and use a temporary array. This achieves the goal of removing the duplication in the conditional, but is unlikely to be as optimizable for the compiler.
if (message->messageType != kMessageTypeCutCardsArray &&
message->messageType != kMessageTypeQuit) {
should be equivalent to:
if(![#[#(kMessageTypeCutCardsArray),#(kMessageTypeQuit)]
contains:#(message->messageType)]) {
Coming from an extremely spoiled family upbringing (turbo pascal, python, ruby) I'm a bit puzzled when it comes to doing all the household chores myself.
Yesterday was one of these days where I just did not find myself a solution. I had to check whether a value matches one of some other values.
x = some_function_return_value();
if x in (1,4,17,29,35):
That's how I used to write it. Now with Objective-C I obviously can't do that. And I searched the old google, but found no answer, and the old manual, and nothing there, so how do you do this in Objective-C, without doing something cranky like the following?
if (x == 1 || x == 4 || x == 17 || x == ...) {
Edited: in this case it is an (int), I know for NSArray and NSString there are methods for this
If it's about integer values, you can use switch:
switch (x) {
case 1:
case 4:
case 17:
case 29:
case 35:
do_something();
break;
}
Do not forget that in C/C++/Objective-C, the cases fall through to the next by default. You need to add break; statements to prevent that.
For non-integer values, you have to do long if statements with a lot of repetition as C doesn't provide syntactic sugar or features that many scripting languages have to abbreviate this.
Another way would be for example to prepare an array and then do:
if ([myArray containsObject:[NSNumber numberWithInteger:x]])
or even better, use an NSSet for that. This will work for most objects, for example it will also work with strings.
There is a fast enumeration syntax in objective C that uses "in" to loop over collections, however given it requires converting your int values to NSNumbers, it's probably easier to use C here
BOOL success = NO;
int size = 5
NSInteger numbers[size] = {1,4,17,29,35};
for (int i = 0; i < size; i++) {
if (yourValue == numbers[i]) {
success = YES;
break;
}
}
if (success) {
/* do your stuff */
}
admittedly not as nice as python...
Here's my silly program of the day:
bool int_exists_in_array(const int n, const int a[], const size_t elementCount) {
return (0 != elementCount) &&
(n == a[0] || int_exists_in_array(n, a + 1, elementCount - 1U));
}
so this:
if x in (1,4,17,29,35):
becomes:
const int a[] = { 1, 4, 17, 29, 35 };
if (int_exists_in_array(x, a, sizeof(a)/sizeof(a[0]))) {
...
}
You can use NSSet in addition with NSValue.