NSMutableArray check if object already exists - iphone

I am not sure how to go about this. I have an NSMutableArray (addList) which holds all the items to be added to my datasource NSMutableArray.
I now want to check if the object to be added from the addList array already exists in the datasource array. If it does not exist add the item, if exists ignore.
Both the objects have a string variable called iName which i want to compare.
Here is my code snippet
-(void)doneClicked{
for (Item *item in addList){
/*
Here i want to loop through the datasource array
*/
for(Item *existingItem in appDelegate.list){
if([existingItem.iName isEqualToString:item.iName]){
// Do not add
}
else{
[appDelegate insertItem:item];
}
}
}
But i find the item to be added even if it exists.
What am i doing wrong ?

There is a very useful method for this in NSArray i.e. containsObject.
NSArray *array;
array = [NSArray arrayWithObjects: #"Nicola", #"Margherita", #"Luciano", #"Silvia", nil];
if ([array containsObject: #"Nicola"]) // YES
{
// Do something
}

I found a solution, may not be the most efficient of all, but atleast works
NSMutableArray *add=[[NSMutableArray alloc]init];
for (Item *item in addList){
if ([appDelegate.list containsObject:item])
{}
else
[add addObject:item];
}
Then I iterate over the add array and insert items.

Use NSPredicate.
NSArray *list = [[appDelegate.list copy] autorelease];
for (Item *item in addList) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"iName MATCHES %#", item.iName];
NSArray *filteredArray = [list filteredArrayUsingPredicate:predicate];
if ([filteredArray count] > 0) [appDelegate insertItem:item];
}

Did you try indexOfObject:?
-(void)doneClicked{
for (Item *item in addList){
if([appDelegate.list indexOfObject:item] == NSNotFound){
[appDelegate insertItem:item];
}
}
UPDATE: You have a logical mistake, not mistake in code. assume the first array is ['a', 'b', 'c'], and the second is ['a', 'x', 'y', 'z']. When you iterate with 'a' through the second array it won't add 'a' to second array in the first iteration (compare 'a' with 'a') but will add during the second (compare 'a' with 'x'). That is why you should implement isEqual: method (see below) in your 'Item' object and use the code above.
- (BOOL)isEqual:(id)anObject {
if ([anObject isKindOfClass:[Item class]])
return ([self.iName isEqualToString:((Item *)anObject).iName]);
else
return NO;
}

Have a look at NSSet. You can add objects and the object will only be added if the object is unique. You can create a NSSet from an NSArray or vise versa.

You can override isEquals and hash on the object so that it returns a YES / NO based on the comparison of the iName property.
Once you have that you can use...
- (void)removeObjectsInArray:(NSArray *)otherArray
To clean the list before adding all the remaining objects.

NR4TR said correctly but i think one break statement is sufficient
if([existingItem.iName isEqualToString:item.iName]){
// Do not add
break;
}

Convert Lowercase and Trim whitespace and then check..
[string lowercaseString];
and
NSString *trim = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

You compare the addList's first object and appDelegate.list's first object, if they are not equal, you insert the addList's object. The logic is wrong, you should compare one addList's object with every appDelegate.list's object.

Related

error in array cleaning method

I am attempting to use this array cleaning method, and there seems to be an error. I can't spot it, I know the array goes in with 3116 items, comes out with 3116 (and I know for a fact there are three duplicates.
Please advice, thanks!
-(NSArray*) removeDuplicates:(NSArray*)inputArray{
NSMutableArray *arrayToClean = [NSMutableArray arrayWithArray:inputArray];
for (int i =0; i<[arrayToClean count]; i++) {
for (int j=(i+1); j < [arrayToClean count]; j++) {
if ([[arrayToClean objectAtIndex:i] isEqual:[arrayToClean
objectAtIndex:j]]) {
[arrayToClean removeObjectAtIndex:j];
j--;
}
}
}
NSArray *arrayToReturn = [NSArray arrayWithArray:arrayToClean];
return arrayToReturn;
}
NSSet will make this a lot easier:
-(NSArray *)removeDuplicates:(NSArray *)inputArray {
NSSet *unique = [NSSet setWithArray:inputArray];
return [unique allObjects];
}
Please note that a set has no guaranteed order. If you need the objects in the array to be in a specific order then you should sort the resulting array as needed.
It may also be appropriate to use an NSSet instead of the original array, then you don't need to worry about duplicates at all. But this depends on the other needs of your array.
Hey You can use another alternative for this.You can use the NSSet here for this task.
NSSet declares the programmatic interface for static sets of distinct objects
You can use sets as an alternative to arrays when the order of elements isn’t important and performance in testing whether an object is contained in the set is a consideration—while arrays are ordered, testing for membership is slower than with sets.
You Just need To call below method.
-(NSArray *)removeDuplicates:(NSArray *)inputArray {
NSSet *finalData = [NSSet setWithArray:inputArray];
return [finalData allObjects];
}
If really face any problem in above way of cleaning ducplicates then you can try another Alterantive.
-(NSArray *)removeDuplicates:(NSArray *)inputArray {
NSMutableArray *inputArray1=[NSMutableArray arrayWithArray:inputArray];
NSMutableArray *finalARray=[[NSMutableArray alloc]init];
for (id obj in inputArray1)
{
if (![finalARray containsObject:obj])
{
[finalARray addObject: obj];
}
NSLog(#"new array is %#",finalARray);
}
return finalARray;
}
I hope it may help you ...
Here is a helper function I had in a previous project to do the exact same thing
- (NSMutableArray *)removeDuplicates:(NSMutableArray *)sortedArray{
NSMutableSet* valuesAdded = [NSMutableSet set];
NSMutableArray* filteredArray = [[NSMutableArray alloc] init];
NSString* object;
/* Iterate over the array checking if the value is a member of the set. If its not add it
* to the set and to the returning array. If the value is already a member, skip over it.
*/
for (object in sortedArray){
if (![valuesAdded member:object]){
[valuesAdded addObject:object];
[filteredArray addObject:object];
}
}
return filteredArray;
}

How do I find (not remove) duplicates in an NSDictionary of NSArrays?

The title pretty much says it all, but just to clarify: I have an NSMutableDictonary containing several NSMutableArrays. What I would like to do is find any value that is present in multiple arrays (there will not be any duplicates in a single array) and return that value. Can someone please help? Thanks in advance!
Edit: For clarity's sake I will specify some of my variables:
linesMutableDictionary contains a list of Line objects (which are a custom NSObject subclass of mine)
pointsArray is an array inside each Line object and contains the values I am trying to search through.
Basically I am trying to find out which lines share common points (the purpose of my app is geometry based)
- (NSValue*)checkForDupes:(NSMutableDictionary*)dict {
NSMutableArray *derp = [NSMutableArray array];
for (NSString *key in [dict allKeys]) {
Line *temp = (Line*)[dict objectForKey:key];
for (NSValue *val in [temp pointsArray]) {
if ([derp containsObject:val])
return val;
}
[derp addObjectsFromArray:[temp pointsArray]];
}
return nil;
}
this should work
If by duplicates you mean returning YES to isEqual: you could first make an NSSet of all the elements (NSSet cannot, by definition, have duplicates):
NSMutableSet* allElements = [[NSMutableSet alloc] init];
for (NSArray* array in [dictionary allValues]) {
[allElements addObjectsFromArray:array];
}
Now you loop through the elements and check if they are in multiple arrays
NSMutableSet* allDuplicateElements = [[NSMutableSet alloc] init];
for (NSObject* element in allElements) {
NSUInteger count = 0;
for (NSArray* array in [dictionary allValues]) {
if ([array containsObject:element]) count++;
if (count > 1) {
[allDuplicateElements addObject:element];
break;
}
}
}
Then you have your duplicate elements and don't forget to release allElements and allDuplicateElements.

Objective-C: using if/else statement with Plist values

I'm sure this is really basic but I can't see what I'm doing wrong. Can someone help me understand where I'm going wrong please? I'm working in xcode. I'm trying to make different parts of my view appear depending on values saved in a property list. If the value assigned to a particular UITextField is equal to zero then I want to hide that UITextField. I'm trying to do this like this. gross is the name of a UITextField:
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
gross.text = [array objectAtIndex:7];
if ([array objectAtIndex:7 == 0]) {
gross.hidden = YES;
}
else {
gross.hidden = NO;
}
[array release];
I think the problem is something to do with how I've wrote the if/else statement. I know this is really basic but I don't quite understand where I'm going wrong. So Your help is much appreciated.
Code should read:
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
gross.text = [array objectAtIndex:7];
if ([[array objectAtIndex:7] isEqualToString:#"0"]) {
gross.hidden = YES;
} else {
gross.hidden = NO;
}
[array release];
This assumes that the object at index 7 of your array exists and is a string. If it's actually an NSNumber, then you should instead use the conditional
if ([[array objectAtIndex:7] intValue] == 0) {
Note the above line works for a string where the text contains an int, such as #"0" or #"7".
if ([[array objectAtIndex:7] intValue] == 0)
First mistake is position of closing ]. And second one is you probably have NSString in array, as you have assigned that in text property. So you need to convert it to int by using intValue.
If your array contains nsstring then your condition should look like:
if ([[array objectAtIndex:7] intValue] == 0) {
...
or
if ([[array objectAtIndex:7] isEqualToString:#"0"]) {
1st condition will work also if your array contains NSNumbers (not likely in your case as you assign array elements to text property), but will fail if string is not a valid number - in that case intValue will return 0 as well.
2nd condition will work fine if you're sure that your elements are strings and you want to compare exactly with #"0".
Your condition is equivalent to
if ([array objectAtIndex:0])
because == operator has greater priority and evaluates to 0. Comparing array's element to 0 directly also does not make sense as NSArray cannot contain nil objects anyway
It might be easier to get the length of the array first and make sure that it has enough elements and then start accessing the elements themselves.

how to detect if an array isnt empty?

I am trying to detect if an array isn't empty in order to be able to do a certain call.
I tried using if (![array ==nil]) however that doesn't compile.
I'm sure there is a really easy explanation to this.
Update
If array is empty I want to do this:
array = [[NSMutableArray alloc]init];
If it has an object I want to do this:
array = [[userDefaults arrayForKey:#"MyFavorites"] mutableCopy];
If you declared it but did not assign anything to it at all:
NSMutableArray *array;
Then the array will be nil, meaning it isn't there at all so you can't say if it's empty or not, so you can't check anything.
If you did assign something to it, and you want to find out if the existing array is empty or not, that would depend on how you created it first.
If the array was assigned from some convenience method, it's autoreleased, so just do this:
if ([array count] == 0) {
array = [[NSMutableArray alloc] init];
} else {
array = [[userDefaults arrayForKey:#"MyFavorites"] mutableCopy];
}
If the array was assigned from an init or copy method, or it was retained previously, store the count in a temporary variable, release the array and use the temporary variable to decide what to do:
NSInteger count = [array count];
[array release];
if (count == 0) {
array = [[NSMutableArray alloc] init];
} else {
array = [[userDefaults arrayForKey:#"MyFavorites"] mutableCopy];
}
In your case I'd always use without differentation
array = [[userDefaults arrayForKey:#"MyFavorites"] mutableCopy];
and set the default value in the user defaults to an empty array right away at program start before accessing the defaults (from Apple's example):
+ (void)initialize{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary
dictionaryWithObject:[NSArray array] forKey:#"MyFavorites"];
[defaults registerDefaults:appDefaults];
}
See Apple's doc on this.
Supposing you are talking about NSArray, if myArray has not been properly alloced+initialized (what you are trying to check) its reference will be nil, so you can do:
if(myArray) //or even if(myArray != nil) since myArray will be a pointer
{
//properly inizialized
}
else
{
//not properly inited
}
If it's been inited on the other hand, you can test its emptiness by checking the count property which returns the number of elements it contains
if([myArray > 0])
//there is at least one element
}
else
{
//no elements
}
you can use count function of NSArray. it will work on NSMutableArray too....
syntext will be,
int ct=[array count];
ct will have number of items in array.
if it us empty it will be Zero

Testing if NSMutableArray contains a string object

I have a NSMutableArray which contains a few NSString objects. How can I test if the array contains a particular string literal?
I tried [array containsObject:#"teststring"] but that doesn't work.
What you're doing should work fine. For example
NSArray *a = [NSArray arrayWithObjects:#"Foo", #"Bar", #"Baz", nil];
NSLog(#"At index %i", [a indexOfObject:#"Bar"]);
Correctly logs "At index 1" for me. Two possible foibles:
indexOfObject sends isEqual messages to do the comparison - you've not replaced this method in a category?
Make sure you're testing against NSNotFound for failure to locate, and not (say) 0.
[array indexOfObject:object] != NSNotFound
Comparing against string literals only works in code examples. In the real world you often need to compare against NSString* instances in e.g. an array, in which case containsObject fails because it compares against the object, not the value.
You could add a category to your implementation which extends NS(Mutable)Array with a method to check wether it contains the string (or whatever other type you need to compare against);
#implementation NSMutableArray (ContainsString)
-(BOOL) containsString:(NSString*)string
{
for (NSString* str in self) {
if ([str isEqualToString:string])
return YES;
}
return NO;
}
#end
You may also use a predicate:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF IN %#", theArray];
BOOL result = [predicate evaluateWithObject:theString];
for every object
[(NSString *) [array objectAtIndex:i] isEqualToString:#"teststring"];