NSArray with objects that "might" be nil - ios

I have 3 objects that might be or not initialized in a random order.
so, if objects "objectOne, "objectTwo", "objectThree" are initialized in this order with
myArray = [NSArray arrayWithObjects:objectOne,objectTwo,objectThree nil];
all objects get inside the array without problem but in my case objectOne, objectTwo might be nil and objectThree might not be nil, and in this case I would like myArray to return(count) 1.
if objectOne is nil but objectTwo and objectThree are not nil I want my array to return(count) 2.
In these 2 last cases my array always return nil. What would be the best approach to this?

There are no magic method can solve the problem for you, you need to build the array from NSMutableArray
NSMutableArray *array = [NSMutableArray array];
if (objectOne) [array addObject:objectOne];
if (objectTwo) [array addObject:objectTwo];
if (objectThree) [array addObject:objectThree];

arrays can't contain nil. There is a special object, NSNull ([NSNull null]), that serves as a placeholder for nil. You can put NSNull in an array, but I don't think that solves your problem either.
How about this:
Create an empty mutable array.
In 3 separate statements:
If objectOne is not nil, add it to the array
if objectTwo is not nil, add it to the array
If objectThree is not nil, add it to the array.
If you need your objects to be in random order, scramble the array afterwords:
for (int index = 0; index < array.count; index++)
{
int randomIndex = arc4random_uniform()
[array exchangeObjectAtIndex: index withObjectAtIndex: randomIndex];
}
This is known as a Fisher–Yates shuffle. (or a minor variation on Fisher-Yates, anyway.)

If you're doing this rarely and you aren't trying to make things neat, you can, of course, use a mutable array and either add or don't add the items one at a time in code, depending on whether they are nil.
If you're doing this frequently and you want a syntax that looks similar to the array literal notation, you can take advantage of the C preprocessor and C arrays to create a smarter NSArray class constructor that handles nil:
#define NSArrayWithCArray(array) \
[NSArray arrayWithCArray:cArray count:sizeof(cArray) / sizeof(cArray[0])];
id cArray[] = {
object1,
object2,
object3,
...
};
NSArray *array = NSArrayWithCArray(cArray);
and then define a method on NSObject that walks through the C array programmatically, dropping any nil values.
+ (NSArray *)arrayWithCArray:(__strong id[])cArray count:(NSUInteger)count {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];
for (__strong id *item = cArray; item < cArray + count; item++) {
if (*item != nil) {
[array addObject:*item];
}
}
return array;
}
Note: The code above is untested, but at least close enough to give you an idea of how to do it. :-)

Related

How do i get unique contents from my NSMutableArray?

I have a UITableView and am displaying contents from my NSMutableArray. Following is array format
(
{
Name = "ANS";
VersionNo = 6;
},
{
Name = "O-Hydro";
Version = 6;
},
{
Name = "ANS";
Version = 6;
},
{
Name = "ANTIChorosAnticholinergic";
Version = 6;
}
)
From this I need to display only unique "Name" (like in this I can see 2 "ANS" I need only one).
How can I do this in iOS?
I tried following but its not working
uniqueArray= [[NSMutableSet setWithArray: groupDetails] allObjects];
but in this way I can do only for NSArray not NSMutableArray.
Pls help me
You can use following line of code to convert your NSArray to NSMutableArray,
NSArray *uniqueArray= [[NSMutableSet setWithArray:groupDetails] allObjects];
NSMutableArray *myMutableArray = [[NSMutableArray alloc] initWithArray:uniqueArray];
You could simply add mutableCopy.
But wait, before you do it. Arrays and sets have two differences:
Arrays can contain duplicates, sets cannot.
Arrays are ordered, sets are not.
So doing what you are doing, you lose the duplicates (intentionally), but the order, too (probably not intentionally).
I do not know, whether this is important for you, but for other readers it might be. So it is the better approach to do that with NSOrderedSet instead of NSSet:
NSOrderedSet *uniqueList = [NSOrderedSet orderedSetWithArray:array];
In many cases an ordered set is exactly what you want. (Probably it has been from the very beginning and the usage of NSArray was wrong. But sometimes you get an array.) If you really want an array at the end of the day, you can reconvert it:
array = [uniqueList.array mutableCopy];
If you just want an array of unique name values, you can use #distinctUnionOfObjects with valueForKeyPath -
NSArray *uniqueArray=[groupDetails valueForKeyPath:#"#distinctUnionOfObjects.name"];
But if you want the array to contain the dictionaries that correspond to the unique names then you need to do a little more work -
NSMutableArray *uniqueArray=[NSMutableArray new];
NSMutableSet *nameSet=[NSMutableSet new];
for (NSDictionary *dict in groupDetails) {
NSString *name=dict[#"name"];
if (![nameSet containsObject:name]) {
[uniqueArray addObject:dict];
[nameSet addObject:name];
}
}

Capitalized NSArray of Strings?

I have an NSarray called array. And it look like this
array = #[#"one", #"two", #"three"];
I want this array to be capitalized. What is the best way to go about this. I can only think of making an NSMutableArray called mutableArray.
And do something like this
for(int i = 0; i < array.lenght; i++) {
self.mutableArray = addObject:[array[i] capitalizedString];
}
Or is there another better way?
The magic method you are looking for does in fact exist.
NSArray *array = #[#"one", #"two", #"three"];
NSArray *capArray = [array valueForKeyPath:#"capitalizedString"];
SWIFT
You Can use map
let array = ["one", "two", "three"]
let upercaseArray = array.map({$0.uppercased()})
now you have upercaseArray like ["ONE","TWO","THREE""]
What you really want is a sort of transform method, which takes an array and a selector, then returns an array of the results of performing that selector on each object. Unfortunately that doesn't exist in vanilla objective-C.
Your approach is generally fine, but I would be careful of two points. Firstly, make sure you create the NSMutableArray with the capacity of the NSArray you are copying, as this will avoid any reallocation overhead as you add objects to it. Secondly, you might want to copy the mutable array so you end up with an immutable NSArray as the final result.
So I would use something like this:
- (NSArray *)capitalizeStringArray:(NSArray *)array {
// Initialize tempArray with size of array
NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:array.count];
for (NSString *str in array) {
[tempArray addObject:[str capitalizedString]];
}
return [tempArray copy]; // convert back to NSArray]
}
You can convert this to a category method on NSArray if you like, and generalize it to use other selectors if you wish.
There's about a gazillion ways to handle this. For small arrays, pick whichever you find easier to understand.
I'd probably use code like this:
- (NSMutableArray *) capitalizedArrayFromArrayOfStrings: (NSArray*) array;
{
NSMutableArray *result = [NSMutableArray arrayWithCapacity: array.count];
for (NSString *string in array)
{
if ([string isKindOfClass: [NSString class]]
[result addObject: [string capitalizedString];
}
}
Creating your array with the correct capacity at the beginning enables the array to allocate enough space for all it's future elements and saves it having to allocate more space later.
Using for..in fast enumeration syntax is more efficient than using array indexing, but for short arrays the difference is small. The code is also simpler to write and simpler to read, so I prefer that syntax where possible.
As Alex says, you could also create a category method on NSArray that would return a capitalized version of your array, or even a category on NSMutableArray that would replace the strings in the array "in place".
Works like charm.
NSString *myString = YOUR_ARRAY.uppercaseString;
[myNSMutableArray addObject:myString];

Enumerating array of objects

I have array of objects and some objects in it have the same value(for example user's guid).
I want find all object with same guide and remove all of then rather then first.
What is the best way to do it?
You can use the NSMUtableArray's removeObject method. Notice that your object should implement the isEqual method appropriately.
[NSMutableArray removeObject]
as per the description:
This method uses indexOfObject: to locate matches and then removes
them by using removeObjectAtIndex:. Thus, matches are determined on
the basis of an object’s response to the isEqual: message. If the
array does not contain anObject, the method has no effect (although it
does incur the overhead of searching the contents).
So, first of all you array need to be mutable NSMutableArray, then the process is:
consider the actual object;
check if is present another object equal to this in the other objects;
if yes, delete the equal objects include the actual.
-
NSMutableArray *arr = [NSMutableArray arrayWithArray:#[#1, #2, #3, #2, #5, #3]];
for(int i=0; i<[arr count]; i++) {
id obj = arr[i];
if([arr indexOfObject:obj inRange:NSMakeRange(i+1, [arr count]-i-1)] != NSNotFound) {
[arr removeObject:obj inRange:NSMakeRange(i, [arr count]-i)];
i--;
}
}

Sort NSMutableArray with objects [duplicate]

This question already has answers here:
How do I sort an NSMutableArray with custom objects in it?
(27 answers)
Closed 9 years ago.
Hopefully someone can help.
I'm adding multiple objects to a NSMutableArray and I need to sort the order based on the first element which will always be a number.
However I'm unsure how to do this?
For example:
NSMutableArray *array = [[NSMutableArray alloc] init];
NSArray *object = [NSArray arrayWithObjects: #"1",#"Test",#"Test"];
[array addObject:object];
Thanks
If your array always contains other arrays, and the first element of the innermost array is always a string containing a number, you could use the NSMutableArray method sortUsingComparator to sort your array:
[array sortUsingComparator: ^(NSArray* obj1, NSArray* obj2)
{
int value1 = [obj1[0] integerValue];
int value2 = [obj2[0] integerValue];
if (value1==value2)
return NSOrderedSame;
else if (value1 < value2)
return NSOrderedAscending;
else
return NSOrderedDescending;
}
];
In the sortUsingComparator family of methods, you supply a block of code that the sort method uses to compare pairs of objects in your array. The block uses the standard typedef NSComparator, which takes 2 objects as parameters and returns a value of type NSComparisonResult.
The code above will probably crash if all the objects in your array are not arrays of strings. (Actually it would work if the first element of each component array was an NSNumber, since NSNumber also responds to the integerValue message.)
If you are going to use this code in a very controlled environment where you can be sure that the data you are sorting is well-formed, it should work as written. If there is any chance that the objects in the array would be of a different type, or be empty, or that their first element would not respond to the integerValue messages, then you should add error checking code.
If you sort your array alphanumerically, the object #"1" will appear before any words. Keep in mind though that #"1" in your code above is a string, not a number.
As to how to sort an array, look into [NSArray sortedArrayUsingComparator:] and similar methods.

How to check if a NSArray has the values of another array

I have my array unique that is my main array and my array kind. I need to check that only 1 value of kind is present in the array unique. Then if there is more than 1 value of the array kind in unique I need to unset all values but the first one used in the array.
The further i got to achieve this is with the following code but I can not store the indexpath of the found object to do a later comparison. xcode says "bad receiver type nsinteger"
could anyone help me to achieve this?
kind = #[#"#Routine",#"#Exercise",#"#Username"];
NSMutableArray *uniqueKind = [NSMutableArray array];
for (NSString* obj in kind) {
if ( [unique containsObject:obj] ) {
NSInteger i = [unique indexOfObject:obj];
[uniqueKind addObject: [i intValue]];
}
}
An NSInteger is like an int, so you can't send it a message ([i intValue]). Also, you can't add an NSInteger to an array without making it an NSNumber or some other object type. You can do it like this:
NSInteger i = [unique indexOfObject:obj];
[uniqueKind addObject: [NSNumber numberWithInteger:i]];
Also (without understanding what you're doing) you might want to use an NSSet instead of an array. And you can combine a couple of calls:
NSUInteger i = [unique indexOfObject:obj];
if ( i != NSNotFound ) {
[uniqueKind addObject:[NSNumber numberWithInteger:i]];
}
I'm not sure if it would solve your problem, but have you considered using sets (or mutable variation) instead of arrays? They ensure uniqueness and they allow you to check for intersection/containment. See the NSSet class reference.
You have to add objects to the NSMutableArray, not the actual intValue. Try converting teh integer to a NSNumber first.
[uniqueKind addObject: [NSNumber numberWithInt:i]];
instead.
(edited )

Resources