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
Related
I have NSMutableArray of NSMutableArrays:
NSMutableArray *array = [[NSMutableArray alloc]init];
for (int i = 0; i < 5; i++)
{
NSMutableArray *miniArray = [[NSMutableArray alloc]init];
for (int k = 0; k < 30; k++)
{
[miniArray addObject:#"0"];
}
[array addObject:miniArray];
}
Then, when I try to do this:
[[array objectAtIndex:packIndex]replaceObjectAtIndex:index withObject:#"1"];
it crashes with: [__NSCFArray replaceObjectAtIndex:withObject:]: mutating method sent to immutable object'
Why ? How to fix ? Thanks !
UPD:
I save this array in NSUserDefaults:
[defaults setObject:array forKey:#"mainArray"];
Then, I read it in the other class:
array = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"mainArray"]];
Also, I must to mention that sometimes the code runs well and it changes "0" to "1". But it also crashes sometimes. So I cant see the logic, why it works fine or why it crashes sometimes.
The problem is that when you read the array out of NSUserDefaults, the mini-arrays are not automatically NSMutableArrays.
Try this:
array = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"mainArray"]];
for(int i = 0; i < array.count; i++) {
NSArray * tempArray = array[i];
array[i] = [tempArray mutableCopy];
}
Edit:
Best Coder's answer explains why this is.
Objects stored in NSUserDefaults are stored as immutable versions, basically NSUserDefaults is a plist and there is no flag marking an array as mutable/immutable so when you read them back out, they are assumed to be immutable.
Values returned from NSUserDefaults are immutable, even if you set a
mutable object as the value. For example, if you set a mutable string
as the value for "MyStringDefault", the string you later retrieve
using stringForKey: will be immutable.
Instead, make a mutableCopy of the array you retrieve from NSUserDefaults, add your object, then set your new array back in.
see this link:
https://developer.apple.com/documentation/foundation/nsuserdefaults
Try using more verbose code:
NSMutableArray *tempArray = [array objectAtIndex:packIndex];
[tempArray replaceObjectAtIndex:index withObject:#"1"];
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;
}
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.
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.
I want to know that how can I add NSMutableArray in to an NSMutableArray so that previous data should not lost, and new data will be added on next indexes.
If you don't understand it then you can ask again to me,
I will appraise the right answer.
my code is as below
-(void)setArray1:(NSMutableArray *)arrayValueFromNew
{
self.myArray=arrayValueFromNew;
myArray2 = [[NSMutableArray alloc] initWithArray:arrayValueFromNew];
for(int i=0;i<[myArray2 count];i++)
{
[myArray addObject:[myArray2 objectAtIndex:i]];
}
}
In your code, myArray and myArray2, both have same objects as you are assigning the arrayValueFromNew array to both. So it kind of doesn't make sense.
But to answer your question 'how to add one array to another?' do :
[mutableArray1
addObjectsFromArray:array2];
EDIT:
this is how your method should look
-(void)setArray1:(NSMutableArray *)arrayValueFromNew
{
if(!self.myArray)
{
self.myArray = arrayValueFromNew;
}
else
{
[self.myArray addObjectsFromArray:arrayValueFromNew];
}
}
Your 'myArray must be initialized. You can initialize it in viewDidLoad or init:
self.myArray = [[NSMutableArray alloc]
initWithCapacity:1];
NSMutableArray *array1 = [NSMutableArray array], *array2 = [NSMutableArray array];
// add some objects to the arrays
[array1 addObjectsFromArray:array2];
//array1 now contains all the objects originally in array1 and array2
This will work,
NSMutableArray *mutarr=[[NSMutableArray alloc]initWithArray: array1]
It looks like you just want a new copy of the old array. There is a handy function for that
NSMutableArray *newArray = [oldArray mutableCopy];
Remember that you've used copy in getting this array so you are responsible for managing the memory of newArray
EDIT
What is your code doing?
-(void)setArray1:(NSMutableArray *)arrayValueFromNew //1
{
self.myArray=arrayValueFromNew; //2
myArray2 = [[NSMutableArray alloc] initWithArray:arrayValueFromNew]; //3
for(int i=0;i<[myArray2 count];i++)
{
[myArray addObject:[myArray2 objectAtIndex:i]]; //4
}
}
This looks like a setter for a property array1
You are setting the property 'array' to arrayValueFromNew. Since I don't know whether this property has been declared with retain or copy I don't know whether array is a pointer to arrayValueFromNew or a pointer to a copy of arrayValueFromNew
You set myArray2 to be a new array that contains the objects of arrayValueFromNew
For each object in myArray2 (which are the objects from arrayValueFromNew. see point 3) you add this object to myArray. Assuming myArray is an NSMutableArray it started with the objects from arrayValueFromNew which you have now added again. It contains each item in arrayValueFromNew twice.