Using many integers in Objective-C - objective-c

I'm new to programming, I have some basic python programming from college, I am familiar with some of the OOP basics and would like some help with managing large amounts of integers. I have 88 of them. 7 will be used for capturing user input and the other 81 will be used for a specific calculation. Instead of writing the following code:
int currentPlace;
int futurePlace;
int speed;
int distance;
int place1 = 1;
int place2 = 2;
int place3 = 3;
// etc...
int place81 = 81;
And then later coming back to the integers and asking user defined questions such as:
NSLog(#"What place is the runner in?");
scanf("%i", &currentPlace);
NSLog(#"What place does the runner finish in?");
scanf("%i", &futurePlace);
NSLog(#"What is the distance of the track?");
// doing some math
NSLog(#"The runner is running at "i" MPH.",speed);
I remember there being an easier way to use the integers but I keep thinking enums or typedefs.
I'd like for the user to pick a number and not have to run a huge if statement to get the work done to cut the size of the program as much as possible.
This is my first "on my own" application so any helpful pointers would be great.
Thanks.

I haven't understood why you need all these place's, but I also assume that an array would be easier to use here. You can use either NSArray or NSMutableArray. The difference between them is that an NSArray instance can't be changed after being created (you can't add/remove elements) unlike an NSMutableArray.
Using NSArray
NSArray *places = [NSArray arrayWithObjects:[NSNumber numberWithInt:1], [NSNumber numberWithInt:2],[NSNumber numberWithInt:3], ..., [NSNumber numberWithInt:81], nil];
nil at the end means the end of the contents of an array. [NSNumber numberWithInt:1] returns an int given as an argument (we can't straight give an int to the array, as an array expects an object as an argument.
You can access the contents of the array using:
[places objectAtIndex:(NSUInteger)];
Remeber that an array starts counting with 0, so if you want to get 5, you have to do this
[places objectAtIndex:4];
Using NSMutableArray
I suggest that you should use this option.
It's easier to use for here.
NSMutableArray *places = [NSMutableArray array];
for (int i = 1; i < 81; i++)
{
[places addObject:[NSNumber numberWithInt:i]];
}
Then you can access data the same way as in the NSArray:
[places objectAtIndex:0];
This will return 1. You can start the for-cycle with 0. After that the index of an array will correspond to the integer inside, so
[places objectAtIndex:5];
will actually return 5.

Are you thinking of a C array?
int myPlaces[81];
for (int i=0; i<81; i++) {
myPlaces[i] = 0;
}

Related

Calculating value of K without messages

Question:
Find the value of K in myInterViewArray without any messages/calls
I was given this hint:
The numbers in the array will never exceed 1-9.
NSArray *myInterViewArray = #[#2,#1,#3,#9,#9,#8,#7];
Example:
If you send 3, the array will return the 3 biggest values in myInterViewArray * 3. So in the example below, K = 9 + 9 + 8.
--
I was asked this question a while back in an interview and was completely stumped. The first solution that I could think of looked something like this:
Interview Test Array:
[self findingK:myInterViewArray abc:3];
-(int)findingK:(NSArray *)myArray abc:(int)k{ // With Reverse Object Enumerator
myArray = [[[myArray sortedArrayUsingSelector:#selector(compare:)] reverseObjectEnumerator] allObjects];
int tempA = 0;
for (int i = 0; i < k; i++) {
tempA += [[myArray objectAtIndex:i] intValue];
}
k = tempA;
return k;
}
But apparently that was a big no-no. They wanted me to find the value of K without using any messages. That means that I was unable to use sortedArrayUsingSelector and even reverseObjectEnumerator.
Now to the point!
I've been thinking about this for quite a while and I still can't think of an approach without messages. Does anyone have any ideas?
There is only one way to do that and that is bridging the array to CF type and then use plain C, e.g.:
NSArray *array = #[#1, #2, #3];
CFArrayRef cfArray = (__bridge CFArrayRef)(array);
NSLog(#"%#", CFArrayGetValueAtIndex(cfArray, 0));
However, if the value is a NSNumber, you will still need messages to access its numeric value.
Most likely the authors of the question didn't have a very good knowledge of the concept of messages. Maybe they thought that subscripting and property access were not messages or something else.
Using objects in Obj-C without messages is impossible. Every property access, every method call, every method initialization is done using messages.
Rereading the question, they probably wanted you to implement the algorithm without using library functions, e.g. sort (e.g. you could implement a K-heap and use that heap to find the K highest numbers in a for iteration).
I assume what is meant is that you can't mutate the original array. Otherwise, that restriction doesn't make sense.
Here's something that might work:
NSMutableArray *a = [NSMutableArray array];
for (NSNumber *num in array) {
BOOL shouldAdd = NO;
for (int i = a.count - 1; i >= k; i--) {
if ([a[i] intValue] < [num intValue]) {
shouldAdd = YES;
break;
}
}
if (shouldAdd) {
[a addObject:num];
}
}
int result = a[a.count - k];
for (int i = k; k < a.count; k++) {
result += [a[i] intValue];
}
return result;

best way to populate NSArray in this algorithm

I intend to make a program that does the following:
Create an NSArray populated with numbers from 1 to 100,000.
Loop over some code that deletes certain elements of the NSArray when certain conditions are met.
Store the resultant NSArray.
However the above steps will also be looped over many times and so I need a fast way of making this NSArray that has 100,000 number elements.
So what is the fastest way of doing it?
Is there an alternative to iteratively populating an Array using a for loop? Such as an NSArray method that could do this quickly for me?
Or perhaps I could make the NSArray with the 100,000 numbers by any means the first time. And then create every new NSArray (for step 1) by using method arraywithArray? (is it quicker way of doing it?)
Or perhaps you have something completely different in mind that will achieve what I want.
edit: replace NSArray with NSMutableArray in above post
It is difficult to tell in advance which method will be the fastest. I like the block based functions, e.g.
NSMutableArray *array = ...; // your mutable array
NSIndexSet *toBeRemoved = [array indexesOfObjectsPassingTest:^BOOL(NSNumber *num, NSUInteger idx, BOOL *stop) {
// Block is called for each number "num" in the array.
// return YES if the element should be removed and NO otherwise;
}];
[array removeObjectsAtIndexes:toBeRemoved];
You should probably start with a correctly working algorithm and then use Instruments for profiling.
You may want to look at NSMutableIndexSet. It is designed to efficiently store ranges of numbers.
You can initialize it like this:
NSMutableIndexSet *set = [[NSMutableIndexSet alloc]
initWithIndexesInRange:NSMakeRange(1, 100000)];
Then you can remove, for example, 123 from it like this:
[set removeIndex:123];
Or you can remove 400 through 409 like this:
[set removeIndexesInRange:NSMakeRange(400, 10)];
You can iterate through all of the remaining indexes in the set like this:
[set enumerateIndexesUsingBlock:^(NSUInteger i, BOOL *stop) {
NSLog(#"set still includes %lu", (unsigned long)i);
}];
or, more efficiently, like this:
[set enumerateRangesUsingBlock:^(NSRange range, BOOL *stop) {
NSLog(#"set still includes %lu indexes starting at %lu",
(unsigned long)range.length, (unsigned long)range.location);
}];
I'm quite certain it will be fastest to create the array using a c array, then creating an NSArray from that (benchmark coming soon). Depending on how you want to delete the numbers, it may be fastest to do that in the initial loop:
const int max_num = 100000;
...
id *nums = malloc(max_num * sizeof(*nums));
int c = 0;
for(int i = 1; i <= max_num; i++) {
if(!should_skip(i)) nums[c++] = #(i);
}
NSArray *nsa = [NSArray arrayWithObjects:nums count:c];
First benchmark was somewhat surprising. For 100M objects:
NSArray alloc init: 8.6s
NSArray alloc initWithCapacity: 8.6s
id *nums: 6.4s
So an array is faster, but not by as much as I expected.
You can use fast enumeration to search through the array.
for(NSNumber item in myArrayOfNumbers)
{
If(some condition)
{
NSLog(#"Found an Item: %#",item);
}
}
You might want to reconsider what you are doing here. Ask yourself why you want such an array. If your goal is to manipulate an arbitrarily large collection of integers, you'll likely prefer to use NSIndexSet (and its mutable counterpart).
If you really want to manipulate a NSArray in the most efficient way, you will want to implement a dedicated subclass that is especially optimized for this kind of job.

Non-repeating arc4random_uniform

I've been trying to get non-repeating arc4random_uniform to work for ages now for my iPhone app. Been over all the questions and answers relating to this on stackoverflow with no luck and now I'm hoping someone can help me. What I want to do is is choose 13 different random numbers between 1 and 104. I have gotten it to work to the point of it choosing 13 different numbers, but sometimes two of them are the same.
int rand = arc4random_uniform(104);
This is what I'm doing, and then I'm using the rand to choose from an array. If it's easier to shuffle the array and then pick 13 from the top, then I'll try that, but I would need help on how to, since that seems harder.
Thankful for any advice.
There's no guarantee whatsoever that ar4random_uniform() won't repeat. Think about it for a second -- you're asking it to produce a number between 0 and 103. If you do that one hundred and five times, it has no choice but to repeat one of its earlier selections. How could the function know how many times you're going to request a number?
You will either have to check the list of numbers that you've already gotten and request a new one if it's a repeat, or shuffle the array. There should be any number of questions on SO for that. Here's one of the oldest: What's the Best Way to Shuffle an NSMutableArray?.
There's also quite a few questions about non-repeating random numbers: https://stackoverflow.com/search?q=%5Bobjc%5D+non-repeating+random+numbers
You can create an NSMutableSet and implement it like this:
NSMutableArray* numbers = [[NSMutableArray alloc] initWithCapacity: 13];
NSMutableSet* usedValues = [[NSMutableSet alloc] initWithCapacity: 13];
for (int i = 0; i < 13; i++) {
int randomNum = arc4random_uniform(104);
while ([usedValues containsObject: [NSNumber numberWithInt: randomNum]) {
randomNum = arc4random_uniform(104)
}
[[usedValues addObject: [NSNumber numberWithInt: randomNum];
[numbers addObject: [[NSNumber numberWithInt: randomNum];
}
Alternatively you can also create a mutable array of 105 integers each a unique one, and arc4random_uniform([arrayname count]) and then delete that same one from the array, then you'll get a random int each time without repeating (though the smaller the array gets the easier it is to predict what the next number will be, just simple probability)
The best algorithm that I have found for this exact question is described here:
Algorithm to select a single, random combination of values?
Instead of shuffling an array of 104 elements, you just need to loop through 13 times. Here is my implementation of the algorithm in Objective C:
// Implementation of the Floyd algorithm from Programming Pearls.
// Returns a NSSet of num_values from 0 to max_value - 1.
static NSSet* getUniqueRandomNumbers(int num_values, int max_value) {
assert(max_value >= num_values);
NSMutableSet* set = [NSMutableSet setWithCapacity:num_values];
for (int i = max_value - num_values; i < max_value; ++i) {
NSNumber* rand = [NSNumber numberWithInt:arc4random_uniform(i)];
if ([set containsObject:rand]) {
[set addObject:[NSNumber numberWithInt:i]];
} else {
[set addObject:rand];
}
}
return set;
}

NSNumbers taking up less memory than ints?

I'm still very much a noob, having a lot of fun learning the basics of Objective-C, using XCode to put together some simple programs for OS-X.
I have a program which ranks a five card poker hand.
Each card in the deck is identified by its unique 'index number' (0-51)
To speed up the evaluator I thought it would be useful to have an array containing all possible combinations of five indices (there are 2598960 of these).
If I do this:
NSMutableArray *allPossibleHands = [[NSMutableArray alloc] initWithObjects: nil];
for(int i = 0; i<48; i++)
{
for(int j = i+1; j<49; j++)
{
for(int k = j+1; k<50; k++)
{
for(int m = k+1; m<51; m++)
{
for(int n = m+1; n<52; n++)
{
NSNumber *number0 = [NSNumber numberWithInt: i];
NSNumber *number1 = [NSNumber numberWithInt: j];
NSNumber *number2 = [NSNumber numberWithInt: k];
NSNumber *number3 = [NSNumber numberWithInt: m];
NSNumber *number4 = [NSNumber numberWithInt: n];
NSArray *nextCombination = [[NSArray alloc] initWithObjects: number0,number1,number2,number3,number4,nil];
[allPossibleHands addObject: nextCombination];
}
}
}
}
}
NSLog(#"finished building allPossibleHands. It contains %i objects", [allPossibleHands count]
);
everything seems to work fine, and I get a message to say that my array contains, as expected, 2598960 objects. I can then list all the elements of my array.
But I thought wrapping my ints in NSNumber objects like that must take up a lot more memory. Maybe storing the index numbers as short ints would be better.
However, if, instead of building my array as above, I do this:
`short int allPossibleHands[2598960][5]`;
intending to then use my loop to store the ints directly, I get a EXC_BAD_ACCESS error message and a note that there's no memory available to the program.
So how come I can store all those NSNumber objects, but not the ints?
Is there some rule about array construction that I'm breaking?
As always, any guidance much appreciated.
Thank You for reading this.
While the second is allocated on the stack (which is much more limited in size), the first one is allocated on the heap and is a pointer to a memory area.
This does not mean that the first one takes less space. If you allocated the second array as a pointer, the error would go away.
Also read the answers to this question.
Assuming that an NSNumber object must store the value and the type of the number, it is probably a little larger than an int.
But if your int[][] array is a local variable, it is very likely stored on the stack, and most stacks are not that large. You could use a pointer to such an array and malloc it on the heap, which probably has enough room for it.
Accessing a C array is very likely a little faster than accessing that many NSNumbers in an NSArray and extracting their values, and if this is for a card game, speed is probably an issue.
I think the problem is where you are storing your array. Is it on the stack? If so, keep in mind it's going to be 25MB so much larger than most stacks allow.

How to create a 2D NSArray or NSMutableArray in objective C?

I want to ask about the objective C question. I want to create a 2D NSArray or NSMutableArray in objective C. What should I do? The object stored in the array is NSString *. Thank you very mcuh.
This is certainly possible, but i think it's worthy to note that NSArrays can only hold objects, not primitive types.
The way to get around this is to use the primitive wrapper type NSNumber.
NSMutableArray *outer = [[NSMutableArray alloc] init];
NSMutableArray *inner = [[NSMutableArray alloc] init];
[inner addObject:[NSNumber numberWithInt:someInt]];
[outer addObject:inner];
[inner release];
//do something with outer here...
//clean up
[outer release];
Try NSMutableDictionary with NSNumbers as keys and arrays as objects. One dimension will be the keys, the other one will be the objects.
To create the specific "2D array"
NSMutableDictionary *twoDArray = [NSMutableDictionary dictionary];
for (int i = 0; i < 10; i++){
[twoDArray setObject:arrayOfStrings forKey:[NSNumber numberWithInt:i]];
}
To pull the data
NSString *string = [[twoDArray objectForKey:[NSNumber numberWithInt:3]] objectAtIndex:5];
//will pull string from row 3 column 5 -> as an example
Edited to make my answer more applicable to the question. Initially I didn't notice that you were looking for a 2D array. If you know how many by how many you need up front you can interleave the data and have a stride. I know that there are probably other (more objective standard) ways of having arrays inside of an array but to me that gets confusing. An array inside of an array is not a 2 dimensional array. It's just a second dimension in ONE of the objects. You'd have to add an array to each object, and that's not what I think of as a 2 dimensional array. Right or wrong I usually do things in a way that makes sense to me.
So lets say you need a 6x6 array:
int arrayStride=6;
int arrayDepth=6;
NSMutableArray *newArray = [[NSMutableArray alloc] initWithCapacity:arrayStride*arrayDepth];
I prefer to initialize the array by filling it up with objects;
for(int i=0; i<arrayStride*arrayDepth; i++) [newArray addObject #"whatever"];
Then after that you can access objects by firstDim + secondDim*6
int firstDim = 4;
int secondDim = 2;
NSString *nextString = [newArray objectAtIndex:firstDim+secondDim*6];