Register FAQ / Rules Forum Spy Search Today's Posts Mark Forums Read
Go Back   MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Reply
 
Thread Tools Search this Thread Display Modes
Old Feb 12, 2009, 12:27 PM   #1
cm0s
macrumors newbie
 
Join Date: Feb 2009
Mutating an array while enumerating

Hello,

files is an array of File objects.
I want to enumerate through the file array and check for File objects that has equal md5 digest.
I want to remove the file objects from the array that are copies of currentFile, but I can't remove objects from the files array while it's enumerating. Can I achieve this by some other means?

Code:
for (File *currentFile in files) {
	NSPredicate *predicate = [NSPredicate predicateWithFormat: @"md5Hash == %@ && filePath != %@", [currentFile md5Hash], [currentFile filePath]]; // This will check for files that has equal md5 digest but not the same filepath (ie true if it's a file duplicate)
		
	if ([[files filteredArrayUsingPredicate:predicate] count] > 0) // If copies are found
	{
		[currentFile addCopies:[files filteredArrayUsingPredicate:predicate]]; // The file class has an array which stores its copies
		[files removeObjectsInArray:[files filteredArrayUsingPredicate:predicate]]; // Can't do this. :(
	}	
}

Last edited by cm0s; Feb 12, 2009 at 12:32 PM.
cm0s is offline   0 Reply With Quote
Old Feb 12, 2009, 01:59 PM   #2
HiRez
macrumors 601
 
HiRez's Avatar
 
Join Date: Jan 2004
Location: Western US
Instead of using an enumerator, just use a simple while loop with an integer index, which you will use to access the array elements using objectAtIndex:. Increment the index each time through the loop, unless you remove an element, in which case you will not increment the index since the same index will now point to the object after the one you just deleted (it'll move up a spot in the array). You just need to make sure that your loop termination condition, where you check to see if you're at the last index, gets updated with the new size of the array each time you remove an object (or get the array size dynamically each time through the loop). You could also start at the last index and decrement the index, making sure you don't go below zero and checking for nil in case you removed every object in the array.
__________________
Go outside, the graphics are amazing!
HiRez is offline   0 Reply With Quote
Old Feb 12, 2009, 02:06 PM   #3
MacRumors Guy
macrumors member
 
Join Date: Sep 2008
From the NSEnumerator documentation:

Quote:
Note: It is not safe to modify a mutable collection while enumerating through it. Some enumerators may currently allow enumeration of a collection that is modified, but this behavior is not guaranteed to be supported in the future.
Using the removeObjectAtIndex method you have no performance guarantees.

Last edited by MacRumors Guy; Feb 12, 2009 at 02:52 PM.
MacRumors Guy is offline   0 Reply With Quote
Old Feb 12, 2009, 02:44 PM   #4
Krevnik
macrumors 68020
 
Krevnik's Avatar
 
Join Date: Sep 2003
The problem here is that mutating an array will give you grief, so you need to move the mutate outside the loop. To do that, you need to keep track of what files need to be removed in a separate collection.

Code:
NSMutableArray *filesToRemove = [NSMutableArray array]; // A set would be nicer, but then File needs to have a good hash method.

for (File *currentFile in files) {
        if([filesToRemove containsObject:currentFile]) // Skip Dupes
                continue;

	NSPredicate *predicate = [NSPredicate predicateWithFormat: @"md5Hash == %@ && filePath != %@", [currentFile md5Hash], [currentFile filePath]]; // This will check for files that has equal md5 digest but not the same filepath (ie true if it's a file duplicate)

        NSArray *filteredArray = [files filteredArrayUsingPredicate:predicate];
		
	if ([filteredArray count] > 0) // If copies are found
	{
		[currentFile addCopies:filteredArray];
                [filesToRemove addObjectsFromArray:filteredArray];
	}	
}

[files removeObjectsInArray:filesToRemove];
The code behavior should be identical to the code you had before, but will now work (I think).
__________________
iMac 2013 27", 13" rMBP, iPad 4, iPhone 5s
Krevnik is offline   0 Reply With Quote
Old Feb 12, 2009, 03:36 PM   #5
kpua
macrumors 6502
 
Join Date: Jul 2006
Krevnik's approach is good, but you can also use an NSIndexSet and removeObjectsAtIndexes:. NSIndexSet is a lot lighter weight than another array and it will be more efficient when removing because NSMutableArray won't have to do an -indexOfObject:
kpua is offline   0 Reply With Quote
Old Feb 13, 2009, 06:38 AM   #6
cm0s
Thread Starter
macrumors newbie
 
Join Date: Feb 2009
Thank you very much for the replies.

Krevniks code worked very well, greatly appreciated.

I'll read up on NSIndexSet and see how I can implement it to improve performance.
cm0s is offline   0 Reply With Quote

Reply
MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Similar Threads
thread Thread Starter Forum Replies Last Post
Want RAID Array Mufasa804 Mac Peripherals 4 Sep 25, 2013 04:29 PM
Array Containing Dictionaries ahan.tm iPhone/iPad Programming 2 Nov 18, 2012 10:31 AM
NSMutable Array Help AnonymousInUse iPhone/iPad Programming 12 Oct 11, 2012 03:46 PM
RAID Array help Lord Adama Mac Pro 3 Jun 5, 2012 10:27 PM

Forum Jump

All times are GMT -5. The time now is 01:51 AM.

Mac Rumors | Mac | iPhone | iPhone Game Reviews | iPhone Apps

Mobile Version | Fixed | Fluid | Fluid HD
Copyright 2002-2013, MacRumors.com, LLC