Removing objects from NSMutableArray that are also contained in another NSMutableArray - ios

I have two array, called array1 and array2. I would like to remove every object from array1 that's value of the "nameId" key can be find in both array. Actually I'm trying it in a for loop, but it doesn't make sense. It doesn not crash, it just simply calls the log in the else statement, that I don't understand why happens. Maybe somebody could show me the right solution.
NSMutableArray *newArray = [self.array1 mutableCopy];
for (PFObject * object in newArray) {
PFObject *placeholderObject = object;
for (PFObject *object2 in self.array2) {
if ([placeholderObject[#"nameId"] isEqualToString:object2[#"nameId"]]) {
[self.array1 removeObject:object];
NSLog (#"EXISTING OBJECT FOUND %#", object);
} else {
NSLog(#"UNIQUE OBJECT FOUND %#", idO[#"hirCime"]);
}
}
}

When creating a mutableCopy of an array you create a new array with a copy of every object in it but they aren't the same ones, so object is a member of newArray but is not a member of self.array1 so you can't remove it from that array.
This should work:
// Creates a new empty mutable array
NSMutableArray *newArray = [#[] mutableCopy];
for (PFObject *object in self.array) {
BOOL found = NO;
for (PFObject *object2 in self.array2) {
if ([object[#"nameId"] isEqualToString:object2[#"nameId"]]) {
found = YES;
NSLog (#"EXISTING OBJECT FOUND %#", object);
break;
} else {
NSLog(#"UNIQUE OBJECT FOUND %#", idO[#"hirCime"]);
}
}
if (!found) {
[newArray addObject:[object copy]];
}
}
// And maybe you want this
self.array = newArray;

Related

getting -[NSNull countByEnumeratingWithState:objects:count:]

Im trying to filter through an array and get rid of all the duplicate strings.
NSMutableArray *initialWomensCategoryArray = [NSMutableArray new];
for(NSArray *womensCategoryInnner in [objects valueForKey:#"womensCategory"])
{
for(id object in womensCategoryInnner)
{
[initialWomensCategoryArray addObject:object];
womensDataArray = [[NSMutableArray alloc]init];
for (id obj in initialWomensCategoryArray)
{
if (![womensDataArray containsObject:obj])
{
[womensDataArray addObject: obj];
}
}
}
}
Above Error want to say "You have getting NULL value" when you have add Object into array. So you have two possibility for this error
1) [initialWomensCategoryArray addObject:object]
2) [womensDataArray addObject: obj]
I think you have to check for the first one([initialWomensCategoryArray addObject:object])

Finding distinct array elements based on dictionary key

I have two arrays of key-value pairs. Both these arrays contain different key-value pairs. I want to find elements in the first array that are not part of the second array based on a particular key.
Example:
1st Array - [{id=1, name="foo"},
{id=2, name="bar"}]
2nd Array - [{id=2, name="abc"},
{id=1, name="xyz"}]
Is there a way I can implement the same?
Right now I enumerate through the two arrays like so:
for (NSDictionary *eachPlayer in 1stArray) {
for (NSDictionary *eachPrediction in 2ndArray) {
if (eachPrediction[kId] != eachPlayer[kId]) {
[self.predictPlayerArray addObject:eachPlayer];
}
}
}
But this fails in the above case and adds both the values to the predictionPlayerArray - in the first iteration it adds 1 and in the forth iteration it adds 2. How do I prevent that from happening?
Thanks.
EDIT
I seem to have solved it this way. Not the best solution but it seems to be working:
for (NSDictionary *eachPlayer in arrayOne) {
for (NSDictionary *eachPrediction in arrayTwo) {
if (eachPrediction[kId] == eachPlayer[kId]) {
if ([self.predictPlayerArray containsObject:eachPlayer]) {
[self.predictPlayerArray removeObject:eachPlayer];
}
break;
}
else {
[self.predictPlayerArray addObject:eachPlayer];
}
self.predictPlayerArray = [self.predictPlayerArray valueForKeyPath:#"#distinctUnionOfObjects.self"];
}
}
Something like this should do:
NSArray *array1 = #[#{#"1":#"foo"},#{#"2":#"bar"},#{#"3":#"abc"}];
NSArray *array2 = #[#{#"2":#"abc"},#{#"1":#"abc"},#{#"4":#"foo"}];
NSMutableSet *result = [NSMutableSet new];
for (NSDictionary *dict1 in array1){
[dict1 enumerateKeysAndObjectsUsingBlock:^(id key1, id obj1, BOOL *stop1) {
for (NSDictionary *dict2 in array2) {
[dict2 enumerateKeysAndObjectsUsingBlock:^(id key2, id obj2, BOOL *stop2) {
if ([obj2 isEqual:obj1]){
[result addObject:#{key1:obj1}];
*stop2 = YES;
}
}];
}
}];
}
NSLog(#"result %#", result);
As you has nested dictionaries you should iterate also in them and finally store the result in a set that would prevent to have duplicate entries (if you use a NSMutableArray you will have twice {3:abc})
The log output is:
2015-02-03 13:53:07.897 test[19425:407184] result {(
{
1 = foo;
},
{
3 = abc;
}
)}

NSMutableArray adds same object each time

I am adding object in NSMutableArray it adds but it adds the same object three time instead of different or new.
Calendar Sow Array has data Breedingdate and sow name.
for (SOWObject *object in appDelegate.calenderSowArray) {
temp = object.breedingDate;
NSLog(#"Date %#",temp);
[arrayNew removeAllObjects];
for (indxs = 0; indxs <countOfarray; indxs ++) {
SOWObject *neObject= (SOWObject *)[appDelegate.calenderSowArray objectAtIndex:indxs];
NSLog(#"Breeding Date %#",neObject.breedingDate);
if ([temp isEqualToString:neObject.breedingDate]) {
[arrayNew removeAllObjects];
[arrayNew addObject:neObject];
}
}
[testArray addObject:arrayNew];
}
Try this,
NSMutableArray *testArray = [[NSMutableArray alloc]init];
for (SOWObject *object in appDelegate.calenderSowArray)
{
[testArray addObject:object];
}
This alone should be enough if you want to add all the SOWObject's in appdelegate.calendarSowArray into the TestArray.
Check if the array contains the object before adding. By doing this a particular object will be added only once.
if(![arrayNew containsObject:neObject]) // if arrayNew does not contain neObject, add it to the array
{
add it to the array
}
or if your testArray is adding same objects, then,
if(![testArray containsObject:arrayNew]) // if testArray does not contain arrayNew, add it to the array
{
add it to the array
}
It looks like you are attempting to create an array of arrays, however the inner array always contains exactly one element. If this is what you want then:
for (SOWObject *object in appDelegate.calenderSowArray) {
temp = object.breedingDate;
NSLog(#"Date %#",temp);
for (indxs = 0; indxs <countOfarray; indxs ++) {
SOWObject *neObject= (SOWObject *)[appDelegate.calenderSowArray objectAtIndex:indxs];
NSLog(#"Breeding Date %#",neObject.breedingDate);
if ([temp isEqualToString:neObject.breedingDate]) {
[testArray addObject:#[ neObject ]]; // This creates a new inner-array each time
}
}
}
And if not (you just want an array) then:
[testArray addObject:neObject];

Property Array doesn't add object, temp array does.

So I have this method in which I query some Singleton class to get data, I add it to my mutable array called profile details, but It doesn't get added, if i add it to a temp array first and then use that to assign it to my profile details array it works? What's happening here?
//Property declaration
#property (nonatomic, strong) NSMutableArray *profileDetails;
//Method definition
- (void) getAllProfiles : (NSArray *) profiles
{
if (_myHealthDetailService == nil) {
self.myHealthDetailService = [[MyHealthDetailService alloc] init];
}
if (profiles) {
if (self.currentProfileCounter < [profiles count]) {
MyHealth *profile = [profiles objectAtIndex:self.currentProfileCounter];
[self.myHealthDetailService requestForMyHealthDetailWithHealth:profile completion:^(NSArray *healths) {
self.currentProfileCounter = self.currentProfileCounter + 1;
if (healths) {
NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:healths.count];
for (MyHealth *profile in healths) {
NSLog(#"Adding Proile: %#",profile);
[self.profileDetails addObject:profile];
[tempArray addObject:profile];
NSLog(#"Proile details array after adding %# profile is: %#",profile, self.profileDetails);
NSLog(#"Temp Proile details array after adding %# profile is: %#",profile, tempArray);
}
self.profileDetails = tempArray;
NSLog(#"Proile details array after copying is: %#",self.profileDetails);
}
DashboardHealthCell_iPad *cell = (DashboardHealthCell_iPad *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForItem:DashboardRow_iPadTypeHealth inSection:0]];
NSLog(#"Proile details array is: %#",self.profileDetails);
[cell populateMyHealthProfiles:self.profileDetails];
} failureBlock:^(NSError *error) {
}];
}
}
}
Relevant NSLog output:
2014-03-12 12:45:58.144 CHM[9768:70b] Proile details array after adding <MyHealth: 0xd562ce0> profile is: (null)
2014-03-12 12:45:58.144 CHM[9768:70b] Temp Proile details array after adding <MyHealth: 0xd562ce0> profile is: (
"<MyHealth: 0xd562270>",
"<MyHealth: 0xd5629e0>",
"<MyHealth: 0xd562ce0>"
)
2014-03-12 12:45:58.144 CHM[9768:70b] Proile details array after copying is: (
"<MyHealth: 0xd562270>",
"<MyHealth: 0xd5629e0>",
"<MyHealth: 0xd562ce0>"
)
The problem seems to be that self.profileDetails is nil by the time you invoke
[self.profileDetails addObject:profile];
There's no place where you alloc / init that Array, so nothing gets added. You can probably get rid of your tempArray by doing
// this
profileDetails = [NSMutableArray arrayWithCapacity:healths.count];
// instead of this
NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:healths.count];

getting a "NSOrderedSetArrayProxy was mutated while being enumerated" error without mutation

I have two functions:
one that returns an array that is filled in a block
- (NSArray *)getArray {
NSArray *someValues = #[#0, #42, #23, #5, #8, #2013];
NSArray *filter = #[#42, #23, #5];
//replacing this NSMutableOrderedSet with a NSMutableArray
//and return just matched then, resolves the problem.
//so the exception has to do something with that set.
NSMutableOrderedSet *matched = [[NSMutableOrderedSet alloc] init];
for (id value in someValues) {
[filter enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isEqual:value])
[matched addObject:value];
}];
}
return [matched array];
}
and another one that enumerates the returned array from the first method
- (void)enumArray:(NSArray *)array {
NSEnumerator *enumerator = [array objectEnumerator];
for (id obj in enumerator) {
if ([obj isEqual:#42])
[enumerator nextObject]; // <== this line causes the error!
}
}
If i now do something like that
NSArray *array = [foo getArray];
[foo enumArray:array];
i will get a NSGenericException with following message:
Collection <__NSOrderedSetArrayProxy: 0x123456> was mutated while
being enumerated
where the hell is something mutated. i don't get it. returning a copy from that array solves the problem, but i still don't get it.
The error has do something with the NSMutableOrderedSet, if i replace the set with an array i don't get an exception.
some screenshots, of exception thrown
You are using fast enumeration while altering an enumerator instance.
Basically it is a big no-no to modify an object that you fast enumerate over (that form of the for loop you are using uses fast enumeration). However, you use [enumerator nextObject]; to access the next object from the enumerator, but this modifies the enumerator by removing the current object from it. So it is your use of nextObject within a for...in loop that is mutating the enumerator.
Get past this problem quickly by using a while loop instead of the for loop, a bit like this:
- (void)enumArray:(NSArray *)array {
NSEnumerator *enumerator = [array objectEnumerator];
while ((id obj = [enumerator nextObject])) {
if ([obj isEqual:#42])
[enumerator nextObject];
}
}
This should get past the fast enumeration/mutation problem. Note, I have absolutely no idea why you want to move the enumerator on a step when obj is equal to 42, but am presuming within the context of the entire code-base that this makes sense!
The basic reason is, you can't edit/modify a mutable array while you're going through it.
So here are the two solutions,
1.Please use #synchronized() directive to lock the array while you mutate it.
- (void)enumArray:(NSArray *)array {
NSEnumerator *enumerator = [array objectEnumerator];
for (id obj in enumerator)
{
if ([obj isEqual:#42])
{
#synchronized(enumerator)
{
[enumerator nextObject]; // <== this line causes the error!
}
}
}
}
2.Just do a copy of you NSArray and use it
- (void)enumArray:(NSArray *)array {
NSEnumerator *enumerator = [[array copy] objectEnumerator];
for (id obj in enumerator)
{
if ([obj isEqual:#42])
{
[enumerator nextObject]; // <== this line causes the error!
}
}
}

Resources