retrieving doubles in NSMutableArray converted with [NSNumber numberWithDouble:doubleVar] - objective-c

I am looking for what is probably a simple answer to my novice question. I know that NSMutableArray can only hold objects, so when I put the double into the array I used the [myArray addObject:[NSNumber numberWithDouble:aValue]]; conversion method. What I need to do now is to pull the values out as doubles and average them. I believe I will use the fast enumeration method vs. FoR looping.
I just need to know how to get the following to work.
double total;
total = [myArray objectAtIndex:i]

total = [[myArray objectAtIndex:i] doubleValue];

Related

how to operate on NSNumber in NSNArray created by NSString

i've got some method.
....{
NSString *mean = #"1:1:1:1:1:1:1:1:1";
tab = [self moveSourceArrayToDestinationArray:mean];
....}
-(NSArray*)moveSourceArrayToDestinationArray:(NSString*)sourceArray{
NSArray *destinationArray = [sourceArray componentsSeparatedByString:#":"];
for (NSNumber *number in destinationArray) {
sum += [number doubleValue];
}
NSLog(#"%d", [destinationArray objectAtIndex:1] * 5); // invalid operands to binary expression ('id' and 'int')
return destinationArray;
}
how can i do something mathematic operation on numbers in NSArray?
Your reference to NSNumber in your code is a mistake, and you got lucky that your code didn't throw an unrecognized selector exception. Your destinationArray is an array of NSStrings, not NSNumbers. It just so happens that both NSString and NSNumber have doubleValue and intValue methods. So when you say [number doubleValue] in your loop, you actually end up calling [NSString doubleValue] which of course still returns the number you want. However, if you were to try to call [number shortValue], where shortValue is a selector that only exists in NSNumber and not NSString, your code would throw an exception and not work.
The moral of this answer is that you should remove any reference to NSNumber in your code, or actually convert the objects in destinationArray to NSNumbers. Otherwise, you risk running into more trouble.
The easiest thing to do is to retrieve a numeric value from the NSNumber object, something you already did in your code snippet earlier. For example, try:
NSLog(#"%d", [[destinationArray objectAtIndex:1] intValue] * 5);
See the full list of numeric access functions in the NSNumber documentation under the section titled "Accessing Numeric Values."
Your object at [destionationArray objectAtIndex:index] is likely to be a NSNumber as well. Therefore, you have to to [[destinationArray objectAtIndex:index] doubleValue]at this point, too.

Using many integers in 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;
}

Getting C-style array from objects of NSArray

I have an NSArray arr. It has a bunch of NSNumber objects. I'm trying to calculate statistics analysis on the array using GNU's GSL. GSL takes parameters as C-style arrays.
Is there any mechanism that can, for example, run 'intValue' on all of the objects in a NSArray object, and convert the results that to a C-style array?
I don't really want to copy the contents of the NSArray to a C-style array, as it's a waste of space and cycles, so I'm looking for an alternative.
The mechanism you're describing — run intValue on all the objects in the NSArray and give a C-style array — seems to be exactly the same thing you describe as "a waste of space and cycles." It's also the only real way to do this if you need a C-style array of ints. Best approach I can think of:
int *c_array = malloc(sizeof(int) * [yourArray count]);
[yourArray enumerateObjectsWithOptions:NSEnumerationConcurrent
usingBlock:^(id number, NSUInteger index, BOOL *unused) {
c_array[index] = [number intValue];
}];
Try this:
id *numArray = calloc(sizeof(id), yourArray.count);
[yourArray getObjects: numArray range: NSMakeRange(0, yourArray.count)];
That gives you a C-array of NSNumbers. An alternative that gives you ints:
int *numArray = calloc(sizeof(int), yourArray.count);
for (int i = 0; i< yourArray.count; i++)
numArray[i] = [[yourArray objectAtIndex: i] intValue];
There is no way to tell yourArray to return a C-array of ints directly. NSArray has no concept of the contents it has, except that they are ids, and must be retained and released at the right times. It can at most return a C-array of ids, as in my first example.
You could probably write your own simple array class that contains ints (or floats or doubles, etc.) directly, in an internal C array, but there is no stock class for this.

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 add two NSNumber objects?

Now this must be easy, but how can sum two NSNumber? Is like:
[one floatValue] + [two floatValue]
or exist a better way?
There is not really a better way, but you really should not be doing this if you can avoid it. NSNumber exists as a wrapper to scalar numbers so you can store them in collections and pass them polymorphically with other NSObjects. They are not really used to store numbers in actual math. If you do math on them it is much slower than performing the operation on just the scalars, which is probably why there are no convenience methods for it.
For example:
NSNumber *sum = [NSNumber numberWithFloat:([one floatValue] + [two floatValue])];
Is blowing at a minimum 21 instructions on message dispatches, and however much code the methods take to unbox the and rebox the values (probably a few hundred) to do 1 instruction worth of math.
So if you need to store numbers in dicts use an NSNumber, if you need to pass something that might be a number or string into a function use an NSNumber, but if you just want to do math stick with scalar C types.
NSDecimalNumber (subclass of NSNumber) has all the goodies you are looking for:
– decimalNumberByAdding:
– decimalNumberBySubtracting:
– decimalNumberByMultiplyingBy:
– decimalNumberByDividingBy:
– decimalNumberByRaisingToPower:
...
If computing performance is of interest, then convert to C++ array std::vector or like.
Now I never use C-Arrays anymore; it is too easy to crash using a wrong index or pointer. And very tedious to pair every new [] with delete[].
You can use
NSNumber *sum = #([first integerValue] + [second integerValue]);
Edit:
As observed by ohho, this example is for adding up two NSNumber instances that hold integer values. If you want to add up two NSNumber's that hold floating-point values, you should do the following:
NSNumber *sum = #([first floatValue] + [second floatValue]);
The current top-voted answer is going to lead to hard-to-diagnose bugs and loss of precision due to the use of floats. If you're doing number operations on NSNumber values, you should convert to NSDecimalNumber first and perform operations with those objects instead.
From the documentation:
NSDecimalNumber, an immutable subclass of NSNumber, provides an object-oriented wrapper for doing base-10 arithmetic. An instance can represent any number that can be expressed as mantissa x 10^exponent where mantissa is a decimal integer up to 38 digits long, and exponent is an integer from –128 through 127.
Therefore, you should convert your NSNumber instances to NSDecimalNumbers by way of [NSNumber decimalValue], perform whatever arithmetic you want to, then assign back to an NSNumber when you're done.
In Objective-C:
NSDecimalNumber *a = [NSDecimalNumber decimalNumberWithDecimal:one.decimalValue]
NSDecimalNumber *b = [NSDecimalNumber decimalNumberWithDecimal:two.decimalValue]
NSNumber *result = [a decimalNumberByAdding:b]
In Swift 3:
let a = NSDecimalNumber(decimal: one.decimalValue)
let b = NSDecimalNumber(decimal: two.decimalValue)
let result: NSNumber = a.adding(b)
Why not use NSxEpression?
NSNumber *x = #(4.5), *y = #(-2);
NSExpression *ex = [NSExpression expressionWithFormat:#"(%# + %#)", x, y];
NSNumber *result = [ex expressionValueWithObject:nil context:nil];
NSLog(#"%#",result); // will print out "2.5"
You can also build an NSExpression that can be reused to evaluate with different arguments, like this:
NSExpression *expr = [NSExpression expressionWithFormat: #"(X+Y)"];
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:x, #"X", y, #"Y", nil];
NSLog(#"%#", [expr expressionValueWithObject:parameters context:nil]);
For instance, we can loop evaluating the same parsed expression, each time with a different "Y" value:
for (float f=20; f<30; f+=2.0) {
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:x, #"X", #(f), #"Y", nil];
NSLog(#"%#", [expr expressionValueWithObject:parameters context:nil]);
}
In Swift you can get this functionality by using the Bolt_Swift library https://github.com/williamFalcon/Bolt_Swift.
Example:
var num1 = NSNumber(integer: 20)
var num2 = NSNumber(integer: 25)
print(num1+num2) //prints 45