I'm building a game for iPhone, and I want to add 24 integers together. These 24 integers contain the total number of bombs ignited in each of the 24 levels. Here is the super crummy code i'm using right now:
totalBombs = level1bombs + level2bombs + level3bombs + level4bombs + level5bombs + level6bombs + level7bombs + level8bombs + level9bombs + level10bombs + level11bombs + level12bombs + level13bombs + level14bombs + level15bombs + level16bombs + level17bombs + level18bombs + level19bombs + level20bombs + level21bombs + level22bombs + level23bombs + level24bombs;
How can I simplify this code?
Yes, I realize this is very poor implementation. Please be gentle with your responses.
Make an array of the LevelBombs then do a loop over the array, adding them. In general, any time you have variables with names like
varname1
varname2
varname3
It means you need an array.
As others say, use an array, but an NS[Mutable]Array array is probably overkill for a collection of 24 integers - consider using a C array. E.g.
unsigned LevelBombs[24];
(assuming the number of bombs is never negative!). You can initialize a global like this using a literal:
unsigned LevelBombs[24] = { 27, 42, ..., 36 };
and you can omit the 24 if you do this - C can count. If you omit the size you get the count using:
unsigned count = sizeof(LevelBombs)/sizeof(unsigned);
Individual elements are LevelBombs[index] and a simple loop will give you the total.
Wrap the whole array up in a (singleton) class if you like, with appropriate methods to modify elements, get the total etc. But wrapping each element in an NSNumber and the whole lot in an NSMutableArray is probably just memory (de)allocation work you don't need.
I think you would benefit from using an array to store your bombs.
You could initialize the array in a couple different ways depending on what works best for your. One way would be like this which sets each level to 5.
int numLevels = 25;
NSMutableArray *bombs = [[NSMutableArray alloc] initWithObjects: nil];
for (int i = 0; i < numLevels; i++) {
[bombs addObject:[NSNumber numberWithInt:5]];
}
Or - if you want to initialize the array with different values for each level you would do something like this:
NSMutableArray *bombs = [[NSMutableArray alloc] initWithObjects: [NSNumber numberWithInt:5], [NSNumber numberWithInt:8], [NSNumber numberWithInt:10], [NSNumber numberWithInt:25], [NSNumber numberWithInt:55], [NSNumber numberWithInt:100], [NSNumber numberWithInt:200], nil];
And so on adding a new NSNumber for each level.
Then to access say level 1 you would do this:
NSNumber levelNumBombs = [bombs objectAtIndex:0];
or level 5 like:
NSNumber levelNumBombs = [bombs objectAtIndex:4];
To change level 5 bombs to 66 you would do something like this:
[bombs replaceObjectAtIndex:4 withObject:[NSNumber numberWithInt:66];
Then, to add everything up you would do something like this:
int totalBombs = 0;
for (int i = 0; i < [bombs count]; i++) {
totalBombs += [[bombs objectAtIndex:i] intValue];
}
Related
Sorry for the newbie question, but i cannot find an answer to it.
I have a simple operation. I declare a variable, and then i want to loop through an array of integers and add these to the variable. However, i can't seem to find how to get a += equivalent going in Objective C.
Any help would be awesome.
Code:
NSInteger * result;
for (NSInteger * hour in totalhours)
{
result += hour;
}
NSInteger is not a class, it's a typedef for int. You cannot put it into collections like NSArray directly.
You need to wrap your basic data types (int, char, BOOL, NSInteger (which expands to int)) into NSNumber objects to put them into collections.
NSInteger does work with +=, keep in mind that your code uses pointers to them, which is probably not what you want anyway here.
So
NSInteger a = 1, b = 2;
a += b;
would work.
If you put them with [NSNumber numberWitInt:a]; etc. into an NSArray, this is not that easy and you need to use -intValue methods to extract their values first.
If totalhours actually contains NSNumber objects you need the following:
NSInteger result = 0;
for(NSNumber* n in totalhours)
{
result += [n integerValue];
}
The problem is that you are confusing NSInteger (a typedef for int or long) with a class instance such as NSNumber.
If your totalhours object is an array of NSNumber objects, you'll need to do:
NSInteger result;
for (NSNumber *hour in totalhours)
{
result += [hour integerValue];
}
No problem using the '+=' operator, just be sure about the objects you are working with...
Your code might be :
NSNumber *n; NSUInteger t = 0;
for(n in totalHours) {
t += [n integerValue];
}
// you got your total in t...
The += operation definitly works. All you need to do is initialize your result variable so it has a start value.
E.g. NSInteger * result = 0;
Good luck!
Your problem is probably that you're using a pointer to an NSInteger instead of an actual NSInteger. You're also not initializing it. Try this:
NSInteger result = 0;
for (NSInteger * hour in totalhours)
{
result += *hour;
}
Is it possible to reference a variable with a string and an int, like this:
int number1;
int j = 1;
#"number%i", j = 3; //Hope this makes sense..
The code above gives me warnings and does not work, how could this be done.
I also tried this, but it doesnt work (for quite obvious reasons):
int j = 1;
NSString *refString = [NSString stringWithFormat:#"number%i", j];
refString = 3;
Im really struggling with this, I know how to do it in Javascript, but not in Obj-C, is it possible?
This is an anti-pattern I call the Poor Man's Array. The better way to do this is to use a proper collection like an array instead of a bunch of variables that are secretly related. Done right, the code with an array will usually be a lot shorter and cleaner too.
From what I can infer you are trying to set/retrieve different variables based on the value of j.
You could use a dictionary for this purpose:
NSMutableDictionary *numbers = [NSMutableDictionary dictionary];
int j = 1;
[numbers setObject:[NSNumber numberWithInt:3] forKey:[NSNumber numberWithInt:j]];
And then to retrieve:
[[numbers objectForKey:[NSNumber numberWithInt:j]] intValue];
It's a bit verbose, but you could simplify it by creating a small class.
I have an NSMutableDictionary that possibly contains more than twenty objects.
If it contains more than 20 objects, how should I remove the oldest entries until there is only 20 left?
For example, NSMutableDictionary with objects:
a = "-1640531535";
b = 1013904226;
c = "-626627309";
d = 2027808452;
e = 387276917;
f = "-1253254618";
g = 1401181143;
h = "-239350392";
i = "-1879881927";
With max number of objects: 5, should become:
a = "-1640531535";
b = 1013904226;
c = "-626627309";
d = 2027808452;
e = 387276917;
Thank you.
If all you're looking for is 20 elements, I'd try something like:
NSMutableDictionary* newDict = [NSMutableDictionary new];
int count = 0;
for (id theKey in oldDict)
{
[newDict setObject:[oldDict getObjectForKey:theKey] forKey:theKey];
if (++count == 20)
break;
}
[oldDict release];
oldDict = newDict;
The idea being that you copy the elements of the first 20 keys you find into a new dictionary, then replace the old one with the new one. If you want to iterate the dictionary via other means you could do that too, but the code above wouldn't have to change much.
If the keys are NSNumbers and you know they're sequential, and you want to remove the lower values, then:
int limit=20; //set to whatever you want
int excess = limit - [dict count];
if (excess > 0) {
for (int i = 1; i <= excess; i++) {
[dict removeObjectForKey:[NSNumber numberWithInt:i]];
}
}
If your keys are NSStrings then just create the NSString with the corresponding format.
If your keys are not sequential, then you would have to either have a parallel dictionary with the date of storage for each entry, so you would know when each entry was stored and you can remove the oldest, or you need to use something else entirely (if you are storing sequential integers as keys, wouldn't it be easier to use NSMutableArray?)
I have a set of NSTimeIntervals like this:
NSArray *mySet = [NSArray arrayWithObjects:
[NSNumber numberWithDouble: time1], //
[NSNumber numberWithDouble: time2],
[NSNumber numberWithDouble: time3],
nil];
// suppose that at this time
// time1 = 0.00000
// time2 = 18.3200
// time3 = 21.6500
at some point in my code I want to test if currentTime is greater or equal to one of the times on the array, so I do
// currentTime = 18.32 right now
for (int i=0; i<[mySet count]; i++) {
if (currentTime >= [[mySet objectAtIndex:i] doubleValue]) {
NSLog(#"%d...", i);
}
}
The output should be "1...2..."
but the output is just "1..."
when i = 1,
it is comparing 18.32 to 18.32 and failing to recognize that the value is equal or greater than the other? WTF???
How can that be?
thanks for any help.
Typically when comparing floating point values you want to decide how close one needs to be to the other (an epsilon or error bound), then just check if they are within that. The easiest way to do that is subtract one from the other then check if the absolute value of the result is less than or equal to your epsilon.
Pseudocode:
var values = [...];
var toCheck = ...;
var epsilon = 0.00001;
for (var i = 0; i < length(values); ++i)
if (abs(values[i] - toCheck) <= epsilon)
print "they are close enough"
end
end
If you're trying to do precise calculations, you shouldn't use NSNumber but NSDecimalNumber. The former is just a wrapper for storing numbers as objects whereas the second is designed to preserve precision when doing calculations. It works better than scalars at extreme ranges.
See Numbers and Values Programming Topics for Cocoa
You can't compare double values for equality except for certain cases. (1.00000 == 1.0000) would probably ring true, but (1.3000 == 1.3000) would most likely not. This is because doubles aren't actually decimal numbers; and not all numbers can be represented by a double; your values are likely something like 18.320000123 and 18.320000473; that is to say; there's probably a lot of trailing garbage that is uninteresting at the precision you have chosen, but none the less keep them from comparing as equal.
It doesn't help that you run one of them through NSNumber; twice.
You declare var i as an int and then try to nslog it at as double value without a cast. The log might be failing independent of the precision of your test.
I'm not sure if there is away to do this but it doesnt hurt to ask i'm using regexkitlite to create a iPhone app. Im specifically using the Regex lib to parse some html. My question is in a regular expression such as #"<a href=([^>]*)>([^>]*) - " each match in between the brackets can be placed in an array using
NSString *regexString = #"<a href=([^>]*)>([^>]*) - ";
NSArray *matchArray = [response arrayOfCaptureComponentsMatchedByRegex:regexString];
This stores the matches as :
Array ( Array(ENTIRE_MATCH1, FIRST_BRACKETS1, SECOND_BRACKETS1),
Array(ENTIRE_MATCH2, FIRST_BRACKETS2, SECOND_BRACKETS2),
Array(ENTIRE_MATCH3, FIRST_BRACKETS3, SECOND_BRACKETS3));
Is there a command that would allow be to capture the matches like this instead?
Array ( Array(ENTIRE_MATCH1, ENTIRE_MATCH2, ENTIRE_MATCH3),
Array(FIRST_BRACKETS1, FIRST_BRACKETS2, FIRST_BRACKETS3),
Array(SECOND_BRACKET1, SECOND_BRACKET2, SECOND_BRACKET3));
I know i could do this fairly easily with a for loops or for each loops but i was wondering if there is a function in the regexkitlite library.
Thanks in Advance,
Zen_Silence
If anyone else needs a function to copy a group to another array this look will do it i'm still looking for a better solution if someone has one.
group = [[NSMutableArray alloc] initWithCapacity:[matchArray count]];
for (int i = 0; i < [matchArray count]; i++) {
NSString *temp = [[matchArray objectAtIndex: i] objectAtIndex: 2];
[group addObject: temp];
}