NSArray: Removing every element but the first 20 - objective-c

I have a NSArray with possibly hundreds of elements. I want to remove every element but the 20 first ones. Ideas?

If your array is an NSArray, then you can't remove objects since it's immutable. You'll need to do something like Neo's answer. If your array is an NSMutableArray, you can use the following line to get the first 20 items:
[myArray removeObjectsInRange:NSMakeRange(20, myArray.count - 20)];

You can extract the first 20 items, and re-assign your source array:
NSArray *myHugeArray = [[NSArray alloc] initWithItems:...] // An array with, say, 1000 items
NSArray *tmpArray = [myHugeArray objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 20)]];
[myHugeArray release];
myHugeArray = [tmpArray retain];

Suppose your NSArray is yourArray, do this
NSMutableArray *temp=[[NSMutableArray alloc]initWithArray:yourArray];
for(int i=0; i<20;i++){
[temp addObject:[yourArray objectAtIndex:i]];
}
yourArray=[NSArray arrayWithArray:temp];

Related

NSMutableArray keep objects at indexSet

I am on Xcode 8.2, OSX not iOS, Objective-C
I have an NSMutableArray and an NSIndexSet. I want to remove ALL items of the array EXCEPT those at the NSIndexSet. So basically something like
[array keepObjectsAtIndexes:indexSet]; // just to carify i know this doesnt exist
What's the best way to do this? Can i somehow 'reverse' the index set?
You can construct an inverse of a given NSIndexSet by constructing an index set that has all indexes in range 0..arrayCount-1, inclusive, and then removing the indexes in your indexSet from it:
NSMutableIndexSet *indexesToRemove = [NSMutableIndexSet initWithIndexesInRange:NSMakeRange(0, array.count)];
[indexesToRemove removeIndexes:indexesToKeep];
[array removeObjectsAtIndexes:indexesToRemove];
You can do this even without creating unnecessary arrays:
// Initial array
NSMutableArray* array = [[NSMutableArray alloc] initWithArray:#[#"one", #"two", #"three", #"four", #"five"]];
// Indices we want to keep
NSIndexSet* indexSet = [[NSIndexSet alloc] initWithIndexesInRange:NSMakeRange(1, 3)];
// Preparing reversed index set
NSMutableIndexSet *indexSetToRemove = [[NSMutableIndexSet alloc] initWithIndexesInRange:NSMakeRange(0, [array count])];
[indexSetToRemove removeIndexes:indexSet];
// Removing objects from that set
[array removeObjectsAtIndexes:indexSetToRemove];
The output will be:
2017-05-11 20:10:22.317 Untitled 15[46504:32887351] (
two,
three,
four
)
Cheers
You could get the objects with objectsAtIndexes and replace the entire objects with the result.
NSArray *temp = [array objectsAtIndexes:indexSet];
[array replaceObjectsInRange:NSMakeRange(0, array.count) withObjectsFromArray: temp];

Neater way to write all these parameters

I have a bunch of saved nsuserdefault parameters that need to be written (20 cars to be exact). I am wondering what will be the neatest way to write this. I number it in order because I believe the for loop will be appropriate(not too sure). The code below represents a snippet of what I am trying to do.
NSString *emailBody=[NSString
stringWithFormat:#"%#, %#, %#",[[NSUserDefaults
standardUserDefaults]stringForKey:#"Car1"],[[NSUserDefaults
standardUserDefaults]stringForKey:#"Car2"],[[NSUserDefaults
standardUserDefaults]stringForKey:#"Car3"]];
There's no reason to save 20 separate items. Just put them in an array and store the array with setObject:forKey:. You can then fetch them all back as an array using stringArrayForKey: (or arrayForKey: or even just objectForKey:).
Once you have an array, creating a comma-separated list is very easy:
NSString *emailBody = [array componentsJoinedByString:#", "];
If you must store them as 20 items for compatibility, I would still pull them out of NSUserDefaults and put them in an array before actually using them.
Just use a for loop, something like this.
NSMutableArray *a = [NSMutableArray array];
for (int i=1;i<21;i++)
{
[a addObject:[NSString stringWithFormat:#"Car%d", i]];
}
Then just put the array into a string.
Slightly neater:
NSMutableString *emailBody = [[NSMutableString alloc] init];
for (unsigned i = 1; i <= 20; i++) {
if (i > 1)
[emailBody appendString:#", "];
[emailBody appendString:[[NSUserDefaults standardUserDefaults]
stringForKey:[StringWithFormat:#"Car%d", i]]];
}

Trying to build polygon from NSString

So, I'm trying to build an array of CGPoints by breaking an NSString, typically look like this:
31.241854,34.788867;31.241716,34.788744;31.242547,34.787585;31.242661,34.787719
Using this code:
- (NSMutableArray *)buildPolygon:(NSString *)polygon
{
NSMutableArray *stringArray = [[NSMutableArray alloc] init];
[stringArray addObject:[polygon componentsSeparatedByString:#";"]];
NSMutableArray *polygonArray = [[NSMutableArray alloc] init];
for (int i=0; i < polygonArray.count; i++)
{
NSArray *polygonStringArray = [[NSArray alloc] init];
polygonStringArray = [[stringArray objectAtIndex:i] componentsSeparatedByString:#","];
CGFloat xCord = [[polygonStringArray objectAtIndex:0] floatValue];
CGFloat yCord = [[polygonStringArray objectAtIndex:1] floatValue];
CGPoint point = CGPointMake(xCord, yCord);
[polygonArray addObject:[NSValue valueWithCGPoint:point]];
}
NSLog(#"return polygonArray: %#", polygonArray);
return polygonArray;
}
But eventually I get an empty array.
What I'm doing wrong?
You're defining polygonArray as an empty array just before the start of your for loop. You should define polygonArray like:
NSArray *polygonArray = [polygon componentsSeparatedByString:#";"];
And you don't even need to bother with that stringArray variable.
You have confusion over alloc & init, and one simple typo...
The confusions first:
NSMutableArray *stringArray = [[NSMutableArray alloc] init];
This creates a new NSMutableArray and stores a reference to it in stringArray. All good so far.
[stringArray addObject:[polygon componentsSeparatedByString:#";"]];
And this obtains a reference to an NSArray ([polygon componentsSeparatedByString:#";"]) and adds it as a single element to the mutable array referenced by stringArray. There is nothing wrong per se with this, but it is not what you want in this case - you just want the array returned by componentsSeparatedByString:. You do this with:
NSArray *stringArray = [polygon componentsSeparatedByString:#";"];
Which takes the reference returned by componentsSeparatedByString: and stores it in the variable stringArray - no alloc or init required as you are not creating the array yourself. You don't even own this array, so if you are using MRC there is no need to release it later.
NSArray *polygonStringArray = [[NSArray alloc] init];
Now this allocates an immutable empty array and stores a reference to it in polygonStringArray. This is not a very useful array, as it contains nothing and cannot be modified! But you don't keep it around long...
polygonStringArray = [[stringArray objectAtIndex:i] componentsSeparatedByString:#","];
This obtains a reference to an array from componentsSeparatedByString: and stores it in polygonStringArray. If you are using MRC this will cause a leak - your pointless zero-length array created above will leak, and a new zero-length array will be created and leaked every time around the loop.
You are confused over allocation - you only need to allocate things you are creating; when you receive a reference to an already allocated object you only need to store that reference. (If using MRC you may also need to retain/release/autorelease it as well - but let's stick with ARC.) So all you needed here was:
NSArray *polygonStringArray = [[stringArray objectAtIndex:i] componentsSeparatedByString:#","];
Now your code is almost correct, just one typo:
for (int i=0; i < polygonArray.count; i++)
Well you are filling polygonArray in this loop and it starts off as empty, what you need is stringArray.count.
HTH

add array to array in array - objC

Man,just like the topic above if i want to make change directly with an exiting mutable array.
i want to know how to add a new array to an exiting array in a mutable array
Thanks for any advise!
The problem which you mentioned to add an array into another array which is contained in the NSMutableArray, it can be done like
NSMutableArray *childArray = [self.ParentArray objectAtIndex:index];
[childArray addObjectsFromArray:yourArrayToAdd];
hope that will solve your problem
Suppose we have an NSMutableArray named numbersArray
numbersArray = [[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9",#"10" , nil];
if you want to add an array to it instead of the original, lets say that array is an random array of its own content:
NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:numbersArray];
for(NSUInteger i = [numbersArray count]; i > 1; i--) {
NSUInteger j = arc4random_uniform(i);
[temp exchangeObjectAtIndex:i-1 withObjectAtIndex:j];
}
numbersArray = temp;
the last line give the numbersArray the content of the temp array
and we can do that with
numbersArray = [temp copy];
for the index exchange you can use exchangeObjectAtIndex as follow:
[numbersArray exchangeObjectAtIndex:0 withObjectAtIndex:3];
[numbersArray exchangeObjectAtIndex:1 withObjectAtIndex:4];
[numbersArray exchangeObjectAtIndex:2 withObjectAtIndex:5];

obj-c fetching strings from array

i'm new to obj-c (this is my first day class eheh) and i'm trying to change a label with a random string from a multidimensional array. plus, every time the button is hitten you switch the array. i know it's a bit odd eheh… this is the IBAction:
UIButton *button = (UIButton *)sender;
NSMutableArray *firstArray = [NSMutableArray array];
[firstArray addObject:#"foo"];
NSMutableArray *secondArray = [NSMutableArray array];
[secondArray addObject:#"bar"];
NSMutableArray *frasi = [NSMutableArray array];
[frasi addObject:firstArray];
[frasi addObject:secondArray];
NSMutableArray *array = [NSMutableArray arrayWithObjects:[frasi objectAtIndex:[button isSelected]], nil];
NSString *q = [array objectAtIndex: (arc4random()% [array count] )];
NSString *lab = [NSString stringWithFormat:#"%#", q];
self.label.text = lab;
all works, but the new label is
( "foo" )
instead of just foo (without quotes)... probably i mess in the last block of code...
ty
So, you create 2 mutable arrays, then add them to a new mutable array frasi. Then you get one of those two arrays and use it as the single element (because you use arrayWithObjects: instead of arrayWithArray:) of a new array array.
So array is an array that contains a single array element (instead of an array of strings as you may believe).
When you get an object from array, it's always the same single object that was used to initialize it: either firstArray or secondArray.
So you get an array of strings where you expect a string. When using stringWithFormat:, the specifier %# is replaced with the string description of that object.
A string returns itself as its own description. But the description of an array is the list of all its elements separated with commas and surrounded by parenthesis, which is why you get ( "foo" ).
So instead or creating unneeded arrays, you may just replace all the 8th last lines with this:
NSArray *array = [button isSelected] ? secondArray : firstArray;
self.label.text = [array objectAtIndex:arc4_uniform([array count])];
Actually u have array within array
Replace this line with yours:
NSString *q = [[array objectAtIndex: (arc4random()% [array count] )] objectAtIndex:0];