seeing if an object exists at index[i] in NSMUtableArray - objective-c

People I'd like to see if an element at index[i] is not present in a different (or current ) array.
So for instance if my array looked somewhat like this
[wer, wer4 , wer5 , werp , klo ...
Then I would like to see if aExerciseRef.IDE ( which is "sdf" for instance ) does or does not exist at index[i].
I assume I'd have to use some sort of iterator ..
for( int i = 0; i < 20; i++ )
{
if([instruct objectAtIndex:index2 + i] != [instruct containsObject:aExerciseRef.IDE] )
NSLog(#"object doesn't exist at this index %i, i );
else
NSLog(#"well does exist")
}
I know this doesn't work , it's just to elaborate what I'd like to achieve.
edit:
I'm going to try to elaborate it a little more and be more specific.
1) First of all aExerciseRef.IDE changes everytime it get's called so one time it is "ret" another time it's "werd".
2) Imagine an array being filled with aExerciseRef.IDE's then I would like to compare if the elements in this array exist in the instruct array.
So I would like to see if the element at let's say position 2 (wtrk)
[wer, wtrk, wer , sla ...
exists in the array which was being filled with the aExerciseRef.IDE's.
I hope I've been more clear this time.

Sir Lord Mighty is partially correct. Yes, your comparison is wrong. No, his solution won't work.
Here's one that will:
if (index < [anArray count] && [[anArray objectAtIndex:index] isEqual:anObject]) {
NSLog(#"Got it!");
} else {
NSLog(#"Don't have it.");
}
Alternatively, you can use the containsObject: method to achieve the same thing:
if ([anArray containsObject:aExerciseRef.IDE]) {
NSLog(#"Got it!");
} else {
NSLog(#"Don't have it.");
}
The second option will not give you the index of the object, but that is easily rectified using:
NSInteger index = NSNotFound;
if ([anArray containsObject:aExerciseRef.IDE]) {
index = [anArray indexOfObject:aExerciseRef.IDE];
...
}

Your example makes no sense at all, and does nothing to clarify the question. You are doing a comparison between an expression with type (id)
[instruct objectAtIndex:index2 + i]
and one with type BOOL
[instruct containsObject:aExerciseRef.IDE]
And if the object you are looking for is at index x in an array, then it goes without saying that containsObject on the array will return YES for that object.
If what you want to accomplish is simply what you state in the title, then it's as easy as:
if ([[anArray objectAtIndex:index] == anObject])
NSLog (#"Got it!");
else
NSLog (#"Don't have it.");

Related

NSMutableArray was mutated while being enumerated

I have an array in an old objective-C app that I am using to learn more "complicated" coding. It is back from the old days of OS X and was very much broken. I have gotten it to work (mostly)! However, the app has an NSMutableArray of images, 7 in total. I use a random number generator to insert the images on the screen, some code to allow them to fall, and then, using screen bounds, when they reach "0" on the Y axis they are removed from the array.
I initially just had:
if( currentFrame.origin.y+currentFrame.size.height <= 0 )
{
[flakesArray removeObject:myItem];
I have read when removing objects from an array it is best practice to iterate in reverse...so I have this bit of code:
for (NSInteger i = myArray.count - 1; i >= 0; i--)
{ //added for for statement
if( currentFrame.origin.y+currentFrame.size.height <= 0 )
{
[myArray removeObjectAtIndex:i];
}
Sadly both methods result in the same mutated while enumerated error. Am I missing something obvious?
If I add an NSLog statement I can get, I think, the index of the item that needs to be removed:
NSLog (#"Shazam! %ld", (long)i);
2017-01-07 14:39:42.086667 MyApp[45995:7500033] Shazam! 2
I have looked through a lot and tried several different methods including this one, which looks to be the most popular with the same error.
Thank you in advance! I will happily provide any additional information!
Adding more:
Sorry guys I am not explicitly calling NSFastEnumeration but I have this:
- (void) drawRectCocoa:(NSRect)rect
{
NSEnumerator* flakesEnum = [flakesArray objectEnumerator];
then
for( i = 0; i < numberToCreate; i++ )
{
[self newObject:self];
}
while( oneFlake = [flakesEnum nextObject] )
It is here where:
if( currentFrame.origin.y+currentFrame.size.height <= 0 )
{
NSLog (#"Shazam! %i", oneFlake);
[flakesArray removeObject:oneFlake];
}
Thank you all. I am learning a lot from this discussion!
There are two ways to go: (1) collect the objects to remove then remove them with removeObjectsInArray:.
NSMutableArray *removeThese = [NSMutableArray array];
for (id item in myArray) {
if (/* item satisfies some condition for removal */) {
[removeThese addObject:item];
}
}
// the following (and any other method that mutates the array) must be done
// *outside of* the loop that enumerates the array
[myArray removeObjectsInArray:removeThese];
Alternatively, reverseObjectEnumeration is tolerant of removes during iteration...
for (id item in [myArray reverseObjectEnumerator]) {
if (/* item satisfies some condition for removal */) {
[myArray removeObject: item];
}
}
As per the error, you may not mutate any NSMutableArray (or any NSMutable... collection) while it is being enumerated as part of any fast enumeration loop (for (... in ...) { ... }).
#danh's answer works as well, but involves allocating a new array of elements. There are two simpler and more efficient ways to filter an array:
[array filterUsingPredicate:[NSPredicate predicateWithBlock:^(id element, NSDictionary<NSString *,id> *bindings) {
// if element should stay, return YES; if it should be removed, return NO
}];
or
NSMutableIndexSet *indicesToRemove = [NSMutableIndexSet new];
for (NSUInteger i = 0; i < array.count; i += 1) {
if (/* array[i] should be removed */) {
[indicesToRemove addIndex:i];
}
}
[array removeObjectsAtIndexes:indicesToRemove];
filterUsingPredicate: will likely be slightly faster (since it uses fast enumeration itself), but depending on the specific application, removeObjectsAtIndexes: may be more flexible.
No matter what, if you're using your array inside a fast enumeration loop, you will have to perform the modification outside of the loop. You can use filterUsingPredicate: to replace the loop altogether, or you can keep the loop and keep track of the indices of the elements you want to remove for later.

Sudoku Backtracking Algorithm Failure

I'm trying to generate a sudoku board, and although I can generate a solution, I now need to remove squares that a user can then fill in. In order to do this, I'd like to use backtracking to check each time that I remove a square, the board is
1. still solvable and 2. has only one solution.
The Problem
When I test my backtracking algorithm on this board (where the zeroes are empty squares), it returns this solution. Obviously I would prefer not to end up with several 9s in the first row, for example.
My Code
- (BOOL) solveArray: (NSArray*) numArray {
NSMutableArray* board = [numArray mutableCopy];
for (int i=0; i<9; i++) { //make all of the arrays mutable as well (since it's 2D)
[board replaceObjectAtIndex:i withObject:[board[i] mutableCopy]];
}
//if everything is filled in, it's done
if (![self findUnassignedLocation:board]) {
NSLog(#"\n%#", [SudokuBoard sudokuBoardWithArray:board]);
return TRUE;
}
NSArray* poss = [[SudokuBoard sudokuBoardWithArray:board] possibleNumbersForRow:self.arow Col:self.acol];
//if there are no options for a location, this didn't work.
if ([poss count] == 0) {
return FALSE;
}
//otherwise, continue recursively until we find a solution
else {
for (int i=0; i<[poss count]; i++) {
//make a tentative assignment
board[self.arow][self.acol] = poss[i];
//return, if successful, done
if ([self solveArray:board]) {
return TRUE;
}
//if that didn't work, unmake it and retry with other options
board[self.arow][self.acol] = [NSNumber numberWithInt:0];
}
}
return FALSE;
}
Any thoughts on where I might be going wrong?
Each level of recursion needs its own row and column variables. That is, row and column should be inputs to solveArray and outputs of findUnassignedLocation instead of being member variables. As it is, when there is backtracking the row and column of the failed level get reused by the caller.
Given that some assigned locations are being overwritten, maybe findUnassignedLocation also contains an error.
Given that the result is invalid, maybe possibleNumbersForRow also contains an error.

compaire NSArray items with every other item in the NSArray

I have an NSArray of NSStrings and would like to know how to compare each item in the array with every other item in the array to see if there is any strings different from the rest.
I have seen a c++ example
for (int i = 0; i < list.size(); i++) {
for (int j = i+1; j < list.size(); j++) {
// compare list.get(i) and list.get(j)
}
}
but was woundering if there is a better easier way in objective C? also the other thing I need to do is make sure the item doesn't compare itself while it loops through.
Any help or examples would be greatly appreciated.
UPDATE ** BOLD is the updated part of the question **
If I read your question correctly, you want the strings that only appear once in the list, correct?
NSCountedSet *counted = [NSCountedSet setWithArray:list];
for (NSString *string in counted) {
NSUInteger count = [counted countForObject:string];
if (count == 1) {
// process "string", it appears in the list just once
}
}
If you just want to know if there is more than one different value in the list then do this:
NSSet *set = [NSSet setWithArray:list];
if (set.count == 1) {
// There is only one distinct value in the list
} else {
// There is more than one distinct value in the list
}
I'd use an NSMutableDictionary. This is very similar to "merging two lists into unique values", the apple docs actually explain the complicated way somewhere. I forgot where I found it, but the easy way is here: Merge two arrays while preserving the original array order
So what you'd do is loop through everything, see if there's a key (set to the string), if not, add one via the setObject: forKey: method, then enumerate through the dictionary or just grab the allKeys value after.
Use two sets. If the string goes into the first set without conflict, add it to the second set. If the string encounters a conflict in the first set, remove it from the second set. When you've processed all the strings the second set contains the unique ones.

fast enumeration for removing item in NSMutableArray crash

i have a strange issue , if i remove my item at forin enumeration , it would crash , so like this:
for (Obstacle *obstacleToTrack in _obstaclesToAnimate) {
//this if else not so important for happening crash
if(obstacleToTrack.distance > 0){
obstacleToTrack.distance -= _playerSpeed * _elapsed;
}else{
if (obstacleToTrack.watchOut) {
obstacleToTrack.watchOut = NO;
}
obstacleToTrack.x -= (_playerSpeed + obstacleToTrack.speed) * _elapsed;
}
if (obstacleToTrack.x < -obstacleToTrack.width || _gameState == GS_OVER) {
[self removeChild:obstacleToTrack];
//this line makes crash happen , if remove this line code work fine
[_obstaclesToAnimate removeObject:obstacleToTrack];
}
}
if i change my code to
NSMutableArray *forRemoving = [[NSMutableArray alloc]init];
for (Obstacle *obstacleToTrack in _obstaclesToAnimate) {
//this if else not so important for happening crash
if(obstacleToTrack.distance > 0){
obstacleToTrack.distance -= _playerSpeed * _elapsed;
}else{
if (obstacleToTrack.watchOut) {
obstacleToTrack.watchOut = NO;
}
obstacleToTrack.x -= (_playerSpeed + obstacleToTrack.speed) * _elapsed;
}
if (obstacleToTrack.x < -obstacleToTrack.width || _gameState == GS_OVER) {
// code change here
[self removeChild:obstacleToTrack];
[forRemoving addObject:obstacleToTrack];
}
}
for(Obstacle *obstacleToTrack in forRemoving){
[_obstaclesToAnimate removeObject:obstacleToTrack];
[forRemoving removeObject:obstacleToTrack];
}
[forRemoving release];
this would work perfect , could someone tell me why?
The answer is that if you remove an object the other objects in that array move postion in the array since an item is removed.
For example we have an array with 4 items, if we remove the first item (item 0) the item that used to be at index 1 is now at index 0 and the item at 2 is now at 1.
Thus the enumeration breaks.
You could solve this by looping thru the array from the count down to 0:
for (int i = [array count]-1; i >= 0; i--) {
id object = [array objectAtIndex:i];
if (some check) {
[array removeObjectAtIndex:i];
}
}
Like rckoenes said, you break the enumaration by removing stuff in the array while iterating through it.
What you can do is to have a second array where you insert the objects that you want to remove. Then, after your enumeration is finished you can remove all the objects that are found in the second array, from your first array.
You must not modify a collection while iterating through its items.
If you iterate index based (i.e. the classical for loop), you can remove things, but be careful about adjusting your index.
Check this link
https://developer.apple.com/library/mac/documentation/cocoa/conceptual/Collections/Articles/Enumerators.html
Enumeration is “safe”—the enumerator has a mutation guard so that if
you attempt to modify the collection during enumeration, an exception
is raised.

For loop variable always evaluating to true

Annoying newbie problem here. This variable isPlayerTouchingAnotherPlayer is being set to true as soon as I touch the piece. I'm almost positive I know why but I can't find a way to display this in log to confirm. I could probably do it by setting different flag numbers for each of the objects but I was hoping there is another way.
The problem is that piece is an object that is also located in p1Array so as soon as I touch it it hits itself and isPlayerTouchingAnotherPlayer is evaluated to true.
Is there a way I could print out the view or image name of the objects touching somehow to confirm this? And furthermore, is there a way to somehow avoid this annoying conflict.
for (int i = 0; i <[p1Array count]; i++) {
UIImageView *tempP1;
tempP1 =[p1Array objectAtIndex:i];
if (CGRectIntersectsRect(piece.frame, tempP1.frame)) {
NSLog(#"selected piece: %#, touched piece: %# ", piece, tempP1);
isPlayerTouchingAnotherPlayer = TRUE;
}
}
why not use fast enumeration and skip the image view you are not interested in checking.
for (UIImageView *imageView in p1Array) {
if (imageView == piece)
continue;
if (CGRectIntersectsRect(imageView.frame, piece.frame)) {
// do whatever
}
}
it seems like you are already printing out the names of the objects touching in the code sample you have provided. if you want to print out specific properties of the objects you can do that to.
as soon as i touch it it hits itself and isPlayerTouchingAnotherPlayer
is evaluated to true.
Then you should get a log message that shows the same object for the selected piece and the touched piece. If that's what's happening, then just add a condition to your if to prevent it:
if (piece != tempP1 && CGRectIntersectsRect(piece.frame, tempP1.frame)) {
Simply
NSLog(#"%# %#", piece, tempP1);
or
NSLog(#"%ld %ld", (NSInteger) piece, (NSInteger) tempP1);
The first will show you the description of the object, the second the address in memory, if it's same address, it's the same object.
You can simply check if it's the same object (pointer) with a simple equal check to exclude the same object :
if (piece != tempP1) {
if (CGRectIntersectsRect(piece.frame, tempP1.frame)) {
...
}
Furthermore, you would like to write this:
for ( int i = 0;
( ( i < [p1Array count] )
&& ( ! isPlayerTouchingAnotherPlayer )
);
i++
) {
...
}