I am new to Objective C and I'm having trouble getting my head around a few things.
I am trying to make a big integer program, from which I read items entered in a string and put them into an individual elements in the array.
I am currently working on an add method which adds elements from both the arrays together to make a big number stored in a final array.
But I'm kind of confused about to get this array I made from the initWithString method into the array method. I have some understanding of self, but I don't really know how to use it in this sense.
#implementation MPInteger
{
}
-(id) initWithString: (NSString *) x
{
self = [super init];
if (self) {
NSMutableArray *intString = [NSMutableArray array];
for (int i = 0; i < [x length]; i++) {
NSString *ch = [x substringWithRange:NSMakeRange(i, 1)];
[intString addObject:ch];
}
}
return self;
}
-(NSString *) description
{
return self.description;
}
-(MPInteger *) add: (MPInteger *) x
{
//NSMutableArray *arr1 = [NSMutableArray arrayWithCapacity:100];
//NSMutableArray *arr2 = [NSMutableArray arrayWithCapacity:100];
//for (int i=0; i < 100; i++) {
//int r = arc4random_uniform(1000);
//NSNumber *n = [NSNumber numberWithInteger:r];
//[arr1 addObject:n];
//[arr2 addObject:n];
// }
self.array = [NSMutableArray initialize];
return x;
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
MPInteger *x = [[MPInteger alloc] initWithString:#"123456789"];
MPInteger *y = [[MPInteger alloc] initWithString:#"123456789"];
[x add: y];
}
}
So I want too add the x and y arrays, but I'm not sure how to get the arrays in the add method. Do I use self to represent one of the arrays and initialise it, and x to represent the other. I don't know if I'm going about it completely the wrong way. Some help to understand would be greatly appreciated.
When referring to self you're actually accessing the current instance of the class. In other languages this may be implemented as this instead. There are a couple ways of designing the approach you're going for but the simplest pattern is probably composition:
#interface MPInteger
{
NSMutableArray *digits;
}
#end
----------------------------------------------------------------------------
#implementation MPInteger
-(id) initWithString: (NSString *) x
{
// Create a new instance of this class (MPInteger) with a default
// constructor and assign it to the current instance (self).
self = [super init];
if (self) {
// Previously we initialized a string, but then threw it out!
// Instead, let's save it to our string representation:
self->digits = [NSMutableArray array];
for (int i = 0; i < [x length]; i++) {
NSString *ch = [x substringWithRange:NSMakeRange(i, 1)];
[self->digits addObject:ch];
}
return self;
}
// Depending on how you want to implement this function, it could return
// a new MPInteger class or update the current instance (self):
-(MPInteger *) add: (MPInteger *) x
{
NSArray *a = self->digits;
NSArray *b = x->digits;
// Have both strings for A + B, so use them to find C:
NSArray *c = ????;
// Return a new instance of MPInteger with the result:
return [ [ MPInteger alloc ] initWithString:c ];
}
#end
Notice that now the MPInteger class has an instance of an NSString object that will exist during the entire lifetime of the MPInteger object. To update/access this string, all you need to do is say:
self->digits
i trying to create my firsy iphone program and i realize that making an array or matrix of 2 dims is difficult for me... :-(
*how and where i declarer somthing like this (take from java) so all the function can see it:
int[] myArray = new int[6];
*how can i trnslete this function:
public int[] sortArray (int[] myArray){
int tmp;
for (int x = 0; x < myArray.length; x++) {
for (int y = x+1; y < 6; y++) {
if (myArray[y] < myArray[x]) {
tmp = myArray[x];
myArray[x] = myArray[y];
myArray[y] = tmp;
}
}
}
return myArray;
}
*and how i call this function?
sortArray(myArray);
thanks for everyone!!!
sharon
You can do it with one line of code:
NSArray *array = #[#[#1, #2, #3],
#[#4, #5, #6],
#[#7, #8, #9]];
Learn about Objective-C literals here.
As in C,
int twoDArray[3][3];
In objective-C
NSArray *a=#[#"apple",#"axe",#"ant"];
NSArray *b=#[#"ball",#"book",#"baby"];
NSArray *c=#[#"cup",#"cat",#"cow"];
NSArray *twoDArray=#[a,b,c];
or in one statement:
NSArray *twoDArray=#[#[#"apple",#"axe",#"ant"],
#[#"ball",#"book",#"baby"],
#[#"cup",#"cat",#"cow"]];
EDIT:
NO need to convert that java function to obj-c method.
To sort the array :
NSArray *sortedArray = [array sortedArrayUsingComparator:^(id str1, id str2) {
return [((NSString *)str1) compare:((NSString *)str2) options:NSNumericSearch];
}];
EDIT 2: (Removed unwanted typecast of nsstring to id and back to string)
NSArray *sortedArray = [array sortedArrayUsingComparator:^(NSString *str1, NSString *str2) {
return [str1 compare:str2 options:NSNumericSearch];
}];
Declare in your respective .h file
NSMutableArray *numbers;
Then in your .m file
numbers = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < 6; i++)
[numbers addObject:[NSNumber numberWithInteger:i]];
and declare it in your .h as
-(NSMutableArray *)sortArray:(NSMutableArray *)numbers;
This is the translated method above in Objective-C:
-(NSMutableArray *)sortArray:(NSMutableArray *)numbers
{
NSInteger tmp = 0;
for(int x = 0; x < [numbers count]; x++)
for(int y = x + 1; y < 6; y++)
if([numbers objectAtIndex:y] < [numbers objectAtIndex:x])
{
tmp = [numbers objectAtIndex:x];
[numbers replaceObjectAtIndex:x withObject:[numbers objectAtIndex:y]];
[numbers replaceObjectAtIndex:y withObject:tmp];
}
return numbers;
}
Also you can call a method in objective-c as follows:
[self sortArray:numbers];
You seem to have (at least) two related-but separate questions here.
1/ how to create an array of numbers
Objective-C arrays come as immutable NSArrays (fixed contents) or mutable NSMutableArrays (you can add delete and shuffle contents around). You sort function as written is asking for a mutable array.
To create and populate an immutable array with NSNumber objects:
NSArray* array = #[#3,#5,#8,#2,#9,#1]; //"#1" is an NSNumber object literal
//access: array[3] etc
Multidimensional:
NSArray* arrayOfArrays #[#[#3,#5,#8],#[#2,#9,#1]];
//access: arrayOfArrays[1][2] etc
To create an empty variable-length mutable array
NSMutableArray* mutableArray = [[NSMutableArray alloc] init];
Create and populate a variable-length mutable array
myArray = [NSMutableArray arrayWithObjects:#3,#5,#8,#2,#9,#1, nil]; //note nil termination
To turn your immutable NSArray into a mutable NSMutableArray
NSMutableArray* mutableArray = [array mutableCopy];
(but take care, this will only render the top level as mutable, if it contains immutable subarrays they will remain immutable)
Objective-C collections (NSArray, NSDictionary, NSSet) can only hold objective-C objects. Therefore if you want to store ints or floats you need to box them into objective-C NSNumber objects before adding to a collection, and unbox them again to access the value.
int x;
float y;
NSNumber xNum = [NSNumber numberWithInt:x]; //box
NSNumber yNum = [NSNumber numberWithFloat:y]; //box
x = [xNum intValue]; //unbox
y = [yNum floatValue]; //unbox
2/ how to translate code
Here is a like-for-like translation:
To create the (mutable) myArray object:
NSMutableArray* myArray = [[NSMutableArray alloc] init];
Populate it:
[myArray addObjects:#3,#6,#8,#1,#9,nil]; //last value is nil to indicate termination
The method:
- sortArray:(NSMutableArray*)myArray
{
id tmp;
for (int x = 0; x < [myArray count]; x++) {
for (int y = x+1; y < 6; y++) {
if ([myArray[y] floatValue] < [myArray[x] floatValue]) {
tmp = myArray[x];
myArray[x] = myArray[y];
myArray[y] = tmp;
}
}
}
}
To call:
[self sortArray:myArray];
To declare with object scope, make a property in your #interface section
#interface myObject:NSObject
#property (nonatomic, strong) NSMutableArray* myArray;
#end
You will still need to create myArray before you can use it:
self.myArray = [[NSMutableArray alloc] init];
but you will be able to set and access it's values from anywhere inside the object thus:
self.myArray
And - if it is in the public header file #interface section - from outside the object thus:
myObject.myArray
I need to reverse my NSArray.
As an example:
[1,2,3,4,5] must become: [5,4,3,2,1]
What is the best way to achieve this?
There is a much easier solution, if you take advantage of the built-in reverseObjectEnumerator method on NSArray, and the allObjects method of NSEnumerator:
NSArray* reversedArray = [[startArray reverseObjectEnumerator] allObjects];
allObjects is documented as returning an array with the objects that have not yet been traversed with nextObject, in order:
This array contains all the remaining objects of the enumerator in enumerated order.
For obtaining a reversed copy of an array, look at danielpunkass' solution using reverseObjectEnumerator.
For reversing a mutable array, you can add the following category to your code:
#implementation NSMutableArray (Reverse)
- (void)reverse {
if ([self count] <= 1)
return;
NSUInteger i = 0;
NSUInteger j = [self count] - 1;
while (i < j) {
[self exchangeObjectAtIndex:i
withObjectAtIndex:j];
i++;
j--;
}
}
#end
Some benchmarks
1. reverseObjectEnumerator allObjects
This is the fastest method:
NSArray *anArray = #[#"aa", #"ab", #"ac", #"ad", #"ae", #"af", #"ag",
#"ah", #"ai", #"aj", #"ak", #"al", #"am", #"an", #"ao", #"ap", #"aq", #"ar", #"as", #"at",
#"au", #"av", #"aw", #"ax", #"ay", #"az", #"ba", #"bb", #"bc", #"bd", #"bf", #"bg", #"bh",
#"bi", #"bj", #"bk", #"bl", #"bm", #"bn", #"bo", #"bp", #"bq", #"br", #"bs", #"bt", #"bu",
#"bv", #"bw", #"bx", #"by", #"bz", #"ca", #"cb", #"cc", #"cd", #"ce", #"cf", #"cg", #"ch",
#"ci", #"cj", #"ck", #"cl", #"cm", #"cn", #"co", #"cp", #"cq", #"cr", #"cs", #"ct", #"cu",
#"cv", #"cw", #"cx", #"cy", #"cz"];
NSDate *methodStart = [NSDate date];
NSArray *reversed = [[anArray reverseObjectEnumerator] allObjects];
NSDate *methodFinish = [NSDate date];
NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
NSLog(#"executionTime = %f", executionTime);
Result: executionTime = 0.000026
2. Iterating over an reverseObjectEnumerator
This is between 1.5x and 2.5x slower:
NSDate *methodStart = [NSDate date];
NSMutableArray *array = [NSMutableArray arrayWithCapacity:[anArray count]];
NSEnumerator *enumerator = [anArray reverseObjectEnumerator];
for (id element in enumerator) {
[array addObject:element];
}
NSDate *methodFinish = [NSDate date];
NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
NSLog(#"executionTime = %f", executionTime);
Result: executionTime = 0.000071
3. sortedArrayUsingComparator
This is between 30x and 40x slower (no surprises here):
NSDate *methodStart = [NSDate date];
NSArray *reversed = [anArray sortedArrayUsingComparator: ^(id obj1, id obj2) {
return [anArray indexOfObject:obj1] < [anArray indexOfObject:obj2] ? NSOrderedDescending : NSOrderedAscending;
}];
NSDate *methodFinish = [NSDate date];
NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
NSLog(#"executionTime = %f", executionTime);
Result: executionTime = 0.001100
So [[anArray reverseObjectEnumerator] allObjects] is the clear winner when it comes to speed and ease.
DasBoot has the right approach, but there are a few mistakes in his code. Here's a completely generic code snippet that will reverse any NSMutableArray in place:
/* Algorithm: swap the object N elements from the top with the object N
* elements from the bottom. Integer division will wrap down, leaving
* the middle element untouched if count is odd.
*/
for(int i = 0; i < [array count] / 2; i++) {
int j = [array count] - i - 1;
[array exchangeObjectAtIndex:i withObjectAtIndex:j];
}
You can wrap that in a C function, or for bonus points, use categories to add it to NSMutableArray. (In that case, 'array' would become 'self'.) You can also optimize it by assigning [array count] to a variable before the loop and using that variable, if you desire.
If you only have a regular NSArray, there's no way to reverse it in place, because NSArrays cannot be modified. But you can make a reversed copy:
NSMutableArray * copy = [NSMutableArray arrayWithCapacity:[array count]];
for(int i = 0; i < [array count]; i++) {
[copy addObject:[array objectAtIndex:[array count] - i - 1]];
}
Or use this little trick to do it in one line:
NSArray * copy = [[array reverseObjectEnumerator] allObjects];
If you just want to loop over an array backwards, you can use a for/in loop with [array reverseObjectEnumerator], but it's likely a bit more efficient to use -enumerateObjectsWithOptions:usingBlock::
[array enumerateObjectsWithOptions:NSEnumerationReverse
usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// This is your loop body. Use the object in obj here.
// If you need the index, it's in idx.
// (This is the best feature of this method, IMHO.)
// Instead of using 'continue', use 'return'.
// Instead of using 'break', set '*stop = YES' and then 'return'.
// Making the surrounding method/block return is tricky and probably
// requires a '__block' variable.
// (This is the worst feature of this method, IMHO.)
}];
(Note: Substantially updated in 2014 with five more years of Foundation experience, a new Objective-C feature or two, and a couple tips from the comments.)
After reviewing the other's answers above and finding Matt Gallagher's discussion here
I propose this:
NSMutableArray * reverseArray = [NSMutableArray arrayWithCapacity:[myArray count]];
for (id element in [myArray reverseObjectEnumerator]) {
[reverseArray addObject:element];
}
As Matt observes:
In the above case, you may wonder if -[NSArray reverseObjectEnumerator] would be run on every iteration of the loop — potentially slowing down the code. <...>
Shortly thereafter, he answers thus:
<...> The "collection" expression is only evaluated once, when the for loop begins. This is the best case, since you can safely put an expensive function in the "collection" expression without impacting upon the per-iteration performance of the loop.
Georg Schölly's categories are very nice. However, for NSMutableArray, using NSUIntegers for the indices results in a crash when the array is empty. The correct code is:
#implementation NSMutableArray (Reverse)
- (void)reverse {
NSInteger i = 0;
NSInteger j = [self count] - 1;
while (i < j) {
[self exchangeObjectAtIndex:i
withObjectAtIndex:j];
i++;
j--;
}
}
#end
The most efficient way to enumerate an array in reverse:
Use enumerateObjectsWithOptions:NSEnumerationReverse usingBlock. Using #JohannesFahrenkrug's benchmark above, this completed 8x quicker than [[array reverseObjectEnumerator] allObjects];:
NSDate *methodStart = [NSDate date];
[anArray enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
//
}];
NSDate *methodFinish = [NSDate date];
NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
NSLog(#"executionTime = %f", executionTime);
NSMutableArray *objMyObject = [NSMutableArray arrayWithArray:[self reverseArray:objArrayToBeReversed]];
// Function reverseArray
-(NSArray *) reverseArray : (NSArray *) myArray {
return [[myArray reverseObjectEnumerator] allObjects];
}
Reverse array and looping through it:
[[[startArray reverseObjectEnumerator] allObjects] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
...
}];
To update this, in Swift it can be done easily with:
array.reverse()
As for me, have you considered how the array was populated in the first place? I was in the process of adding MANY objects to an array, and decided to insert each one at the beginning, pushing any existing objects up by one. Requires a mutable array, in this case.
NSMutableArray *myMutableArray = [[NSMutableArray alloc] initWithCapacity:1];
[myMutableArray insertObject:aNewObject atIndex:0];
Or the Scala-way:
-(NSArray *)reverse
{
if ( self.count < 2 )
return self;
else
return [[self.tail reverse] concat:[NSArray arrayWithObject:self.head]];
}
-(id)head
{
return self.firstObject;
}
-(NSArray *)tail
{
if ( self.count > 1 )
return [self subarrayWithRange:NSMakeRange(1, self.count - 1)];
else
return #[];
}
There is a easy way to do it.
NSArray *myArray = #[#"5",#"4",#"3",#"2",#"1"];
NSMutableArray *myNewArray = [[NSMutableArray alloc] init]; //this object is going to be your new array with inverse order.
for(int i=0; i<[myNewArray count]; i++){
[myNewArray insertObject:[myNewArray objectAtIndex:i] atIndex:0];
}
//other way to do it
for(NSString *eachValue in myArray){
[myNewArray insertObject:eachValue atIndex:0];
}
//in both cases your new array will look like this
NSLog(#"myNewArray: %#", myNewArray);
//[#"1",#"2",#"3",#"4",#"5"]
I hope this helps.
I don't know of any built in method.
But, coding by hand is not too difficult. Assuming the elements of the array you are dealing with are NSNumber objects of integer type, and 'arr' is the NSMutableArray that you want to reverse.
int n = [arr count];
for (int i=0; i<n/2; ++i) {
id c = [[arr objectAtIndex:i] retain];
[arr replaceObjectAtIndex:i withObject:[arr objectAtIndex:n-i-1]];
[arr replaceObjectAtIndex:n-i-1 withObject:c];
}
Since you start with a NSArray then you have to create the mutable array first with the contents of the original NSArray ('origArray').
NSMutableArray * arr = [[NSMutableArray alloc] init];
[arr setArray:origArray];
Edit: Fixed n -> n/2 in the loop count and changed NSNumber to the more generic id due to the suggestions in Brent's answer.
If all you want to do is iterate in reverse, try this:
// iterate backwards
nextIndex = (currentIndex == 0) ? [myArray count] - 1 : (currentIndex - 1) % [myArray count];
You can do the [myArrayCount] once and save it to a local variable (I think its expensive), but I’m also guessing that the compiler will pretty much do the same thing with the code as written above.
Swift 3 syntax :
let reversedArray = array.reversed()
Try this:
for (int i = 0; i < [arr count]; i++)
{
NSString *str1 = [arr objectAtIndex:[arr count]-1];
[arr insertObject:str1 atIndex:i];
[arr removeObjectAtIndex:[arr count]-1];
}
Here is a nice macro that will work for either NSMutableArray OR NSArray:
#define reverseArray(__theArray) {\
if ([__theArray isKindOfClass:[NSMutableArray class]]) {\
if ([(NSMutableArray *)__theArray count] > 1) {\
NSUInteger i = 0;\
NSUInteger j = [(NSMutableArray *)__theArray count]-1;\
while (i < j) {\
[(NSMutableArray *)__theArray exchangeObjectAtIndex:i\
withObjectAtIndex:j];\
i++;\
j--;\
}\
}\
} else if ([__theArray isKindOfClass:[NSArray class]]) {\
__theArray = [[NSArray alloc] initWithArray:[[(NSArray *)__theArray reverseObjectEnumerator] allObjects]];\
}\
}
To use just call: reverseArray(myArray);