NSMutableArray (1 dim) from NSArray (2dim) - ios

I want to make 1 array that will hold all of the other arrays objects and will look like this
("052-6224754","03-6475075","02-6753231")
my code is:
-(NSMutableArray*) getRecepientsPhones
{
NSMutableArray* phones = [[NSMutableArray alloc]init];
//scroll all choosed contacts and retrieve phones to nsstring
if([recepientsFromContacts count]>0)
for (int i=0; i<[recepientsFromContacts count]; i++)
{
NSMutableArray* tempArray = [[NSMutableArray alloc]init];
if(![[[recepientsFromContacts objectAtIndex:i]objectForKey:#"CPhones"]isKindOfClass:[NSNull class]])
{
[tempArray addObject:[[recepientsFromContacts objectAtIndex:i]objectForKey:#"CPhones"]];
for(int j = 0; j<[tempArray count];j++)
{
[phones addObject:[tempArray objectAtIndex:j]];
}
}
}
//lets fetch from that contact
if([personRecepient count]>0)
{
if(![[personRecepient objectForKey:#"CellPhone"]isKindOfClass:[NSNull class]])
[phones addObject:[personRecepient objectForKey:#"CellPhone"]];
}
NSLog(#"%#",phones);
return phones;
}
[[recepientsFromContacts objectAtIndex:i]objectForKey:#"CPhones"]
is 1 or more dimension array (it is array of phone numbers per person , person can have more than 1 number)
example: ("052-6224754","03-6475075")
but my function returns
("052-6224754","03-6475075"),("02-6753231")
which is not good , what should I do to make it 1 array
("052-6224754","03-6475075","02-6753231")

You should change the line
[phones addObject:[tempArray objectAtIndex:j]];
to
[phones addObjectsFromArray:[tempArray objectAtIndex:j]];
This should result in a flattened array of phone numbers.
Then you should head over to codereview.stackexchange.com because there are several issues with your code fragment.
Edit: Here's a cleaned up version of the method:
- (NSArray *)recepientsPhoneNumbers
{
NSMutableArray* phoneNumbers = [NSMutableArray array];
for (NSDictionary *dict in _recepientsFromContacts)
{
id recipientPhoneNumbers = dict[#"CPhones"];
if (recipientPhoneNumbers != [NSNull null])
[phoneNumbers addObjectsFromArray:recipientPhoneNumbers];
}
id recipientPhoneNumbers = _personRecepient[#"CellPhone"];
if (recipientPhoneNumbers != [NSNull null])
[phoneNumbers addObjectsFromArray:recipientPhoneNumbers];
NSLog(#"%#", phoneNumbers);
return phoneNumbers;
}
I applied Cocoa coding conventions, so ivars are now prefixed with underscores.

Related

Count in multi-dimensional array

How would you count this array?
NSArray *sortThisArray = #[#{#"numbers":#[#"One",#"Two"]},
#{#"numbers":#[#"Two",#"One"]},
#{#"numbers":#[#"One",#"Two",#"Three"]},
#{#"numbers":#[#"One",#"Two",#"Three"]},
#{#"numbers":#[#"One",#"Two",#"Three",#"Four"]},
];
The desired result would then be:
NSArray *sortedArray = #[#{#"numbers":#[#"One",#"Two"],
#"occures":#(2)},
#{#"numbers":#[#"One",#"Two",#"Three"],
#"occures":#(2)},
#{#"numbers":#[#"One",#"Two",#"Three",#"Four"],
#"occures":#(1)},
];
I've tried using NSCountedSet and countForObject, but the results are inaccurate. It seems to only count the arrays that are exactly the same. In other words, the array with #[#"Two",#"One"] gets ignored because its not 100% equal to #[#"One",#"Two"], even though they have the same objects and same count.
This should work. You have to have a consistent way to compare your arrays (either sorting like in this example or by moving the NSArray to NSSet).
NSMutableDictionary<NSArray<NSString *> *, NSNumber *> *valueCount = [NSMutableDictionary dictionary];
for (NSDictionary<NSString *, NSArray<NSString *> *> *value in sortThisArray) {
NSArray<NSString *> *numberStrings = [value[#"numbers"] sortedArrayUsingSelector:#selector(compare:)];
valueCount[numberStrings] = #(valueCount[numberStrings].integerValue + 1);
}
NSMutableArray *sortedArray = [NSMutableArray arrayWithCapacity:valueCount.count];
for (NSArray<NSString *> *key in valueCount) {
[sortedArray addObject:#{#"numbers": key, #"occures": valueCount[key]}];
}
May be something like this:
NSMutableArray *mArray = [NSMutableArray arrayWithArray:sortThisArray];
NSMutableArray *result = [[NSMutableArray alloc] init];
while ([mArray count]) {
NSDictionary *obj = [mArray firstObject];
int count = 1;
for (int i=1; i<[mArray count]; i++) {
NSDictionary *sObj = [mArray objectAtIndex:i];
if ([[sObj objectForKey:#"numbers"] count] == [[obj objectForKey:#"numbers"] count]) {
BOOL increase = YES;
for (int j=0; j<[[obj objectForKey:#"numbers"] count]; j++) {
if (![[sObj objectForKey:#"numbers"] containsObject:[[obj objectForKey:#"numbers"] objectAtIndex:j]]) {
increase = NO;
}
}
if (increase) {
count++;
[mArray removeObjectAtIndex:i];
}
}
}
[mArray removeObjectAtIndex:0];
[result addObject:#{#"numbers":obj, #"occurrs":[NSNumber numberWithInteger:count]}];
}
*Code is not tested

Remove array elements and add them at the same index iOS

I am sorting an array.
There are three types of elements in the array.
1. featured
2. organic and
3. claimed.
Among them, I want to sort only organic elements and keep the featured and claimed elements at their own index.
Below is my code in which, I am extracting the claimed and featured indices in a dictionary as key being the index and value is the array element.
//Initialization
NSMutableArray *sortedArray = nil;
NSMutableDictionary *tempFeaturedDictionary = [[NSMutableDictionary alloc]init];
NSMutableDictionary *tempClaimedDictionary = [[NSMutableDictionary alloc]init];
NSMutableArray *tempOrganicArray = [[NSMutableArray alloc]init];
for (int i = 0; i < array.count; i++) {
DRListing *isFeaturedObj = (DRListing*)[array objectAtIndex:i];
if (isFeaturedObj.featured) {
[tempFeaturedDictionary setObject:isFeaturedObj forKey:[#(i)stringValue]];
}else if (isFeaturedObj.claimed)
{
[tempClaimedDictionary setObject:isFeaturedObj forKey:[#(i)stringValue]];
}else
[tempOrganicArray addObject:isFeaturedObj];
}
Again I am adding the claimed and featured back to their original indices after sorting as:
sortedArray = [NSMutableArray arrayWithArray:[tempOrganicArray sortedArrayUsingDescriptors:sortDescriptorsArray]];
for (int i = 0; i<sortedArray.count; i++) {
for (NSString *key in tempFeaturedDictionary) {
if ( [[#(i)stringValue] isEqualToString: key] ) {
[sortedArray insertObject:[tempFeaturedDictionary objectForKey:[#(i)stringValue]] atIndex:i];
}}
for (NSString *key in tempClaimedDictionary) {
if ([[#(i)stringValue]isEqualToString:key ]) {
[sortedArray insertObject:[tempClaimedDictionary objectForKey:[#(i)stringValue]] atIndex:i];
}
}
}
The code works good. Except there is claimed/(and)featured elements at the last index of the 'array'. Because the 'sortedArray' index remains less than the 'array.count' in this scenario.
Thanks in advance.
Update -
I receive response array of type:
[{featured1 featured2}, {organic1, organic2..}, {claimed1}, {featured11, featured12}, {organic11, organic12..}, {claimed2}, ..]
and I am allowed to sort only organic elements within this array. Featured and claimed should not loose their original index position.
I would iterate through the array, extracting the organics to sort. Then sort your organic array. Then iterate through the original array taking either the element from the original array or an element from the sorted organics array as appropriate.
NSMutableArray *organicsArray = [NSMutableArray new];
for (int i = 0; i < array.count; i++) {
DRListing *isFeaturedObj = (DRListing*)array[i];
if ((!isFeaturedObj.featured) && (!isFeaturedObj.claimed)) {
[organicsArray addObject:isFeaturedObj];
}
}
NSMutableArray *sortedOrganicsArray = [[organicsArray sortedArrayUsingDescriptors:sortDescriptorsArray] mutableCopy];
NSMutableArray *outputArray = [NSMutableArray new];
for (int i = 0; i < array.count; i++) {
DRListing *isFeaturedObj = (DRListing*)array[i];
if ((!isFeaturedObj.featured) && (!isFeaturedObj.claimed)) {
[outputArray addObject:sortedOrganicsArray[0]];
[sortedOrganicsArray removeObjectAtIndex:0];
} else {
[outputArray addObject:isFeaturedObject];
}
}
You could possibly make it a little more efficient if you reversed your sort order for the organics array since then you could say
[outputArray addObject:[sortedOrganicsArray lastObject]];
[sortedOrganicsArray removeLastObject];
But if your array isn't particularly large then the performance improvement will probably be negligible.
Maybe this is an alternative:
NSMutableArray *organics = [NSMutableArray new];
NSMutableArray *others = [NSMutableArray new];
for (DRListing *isFeaturedObj in array) {
if (isFeaturedObj.organic) {
[organics addObject:isFeaturedObj];
} else {
[others addObject:isFeaturedObj];
}
}
NSMutableArray *sorted = [NSMutableArray alloc]initWithObjects:organics,others, nil];
You can take the first 2 functions. The others are what I used for testing.
- (DRListing *)getNextObjectFromArray:(NSArray *)array WithStartingIndex:(int)index
{
for (int i=index; i<array.count; i++) {
DRListing *obj = (DRListing*)[array objectAtIndex:i];
if (!obj.featured && !obj.claimed)
{
return obj;
}
}
return nil;
}
- (void)sortArray:(NSMutableArray *)array
{
for (int pass = 0; pass<array.count-1; pass++) {
for (int i=0; i<array.count-1; i++) {
DRListing *obj = [self getNextObjectFromArray:array WithStartingIndex:i];
int foundIndex = (int)[array indexOfObject:obj];
DRListing *obj2 = [self getNextObjectFromArray:array WithStartingIndex:foundIndex+1];
int foundIndex2 = (int)[array indexOfObject:obj2];
if (obj!=nil && obj2 !=nil) {
if (obj.value >= obj2.value) {
[array exchangeObjectAtIndex:foundIndex withObjectAtIndex:foundIndex2];
}
i = foundIndex;
}
}
}
NSLog(#"Sorted Data: %#",array);
}
- (NSMutableArray *)testData
{
NSMutableArray *array = [NSMutableArray new];
for (int i=0; i<20; i++) {
DRListing *obj = [DRListing new];
obj.featured = i*i%2;
obj.claimed = i%2;
obj.value = i*3%10;
[array addObject:obj];
}
NSLog(#"Test Data: %#",array);
return array;
}
#interface DRListing : NSObject
#property (nonatomic) BOOL featured;
#property (nonatomic) BOOL claimed;
#property (nonatomic) int value;
#end

Remove duplicates from NSArray case insensitively using NSSet

NSArray*arr = #[#"ram",#"Ram",#"vinoth",#"kiran",#"kiran"];
NSSet* uniqueName = [[NSSet alloc]initWithArray:arr];
NSLog(#"Unique Names :%#",uniqueName);
Output:
but i need the output as
You could first convert them all to lowercase strings.
NSArray *arr = #[#"ram",#"Ram",#"vinoth",#"kiran",#"kiran"];
NSArray *lowerCaseArr = [arr valueForKey:#"lowercaseString"];
NSSet* uniqueName = [[NSSet alloc] initWithArray:lowerCaseArr];
NSLog(#"Unique Names :%#",uniqueName);
Unique Names :{(
ram,
kiran,
vinoth
)}
Try this:
NSArray *arr = [NSArray arrayWithObjects:#"Ram",#"ram", nil]; //this is your array
NSMutableArray *arr1 = [[NSMutableArray alloc]init]; //make a nsmutableArray
for (int i = 0; i<[arr count]; i++) {
[arr1 addObject:[[arr objectAtIndex:i]lowercaseString]];
}
NSSet *set = [NSSet setWithArray:(NSArray*)arr1];//this set has unique values
This will always preserve casing form that was existing in your original container (although it's undefined which casing):
NSArray<NSString*>* input = ...
NSMutableDictionary* tmp = [[NSMutableDictionary alloc] init];
for (NSString* s in input) {
[tmp setObject:s forKey:[s lowercaseString]];
}
return [tmp allValues];
Create a mutable array the same size as arr. Fill it with lowercaseString versions of each element of arr. Make the set out of that.
#Updated
Using this you remove uppercase string from your array.
NSMutableArray *arr= [[NSMutableArray alloc]initWithObjects:#"ram",#"Ram",#"vinoth",#"kiran", nil];
NSMutableArray *arrCopy = [[NSMutableArray alloc]init];
for (int index = 0 ; index<arr.count; index++) {
NSUInteger count = [[[[arr objectAtIndex:index] componentsSeparatedByCharactersInSet:[[NSCharacterSet uppercaseLetterCharacterSet] invertedSet]] componentsJoinedByString:#""] length];
if (count == 0) {
[arrCopy addObject:[arr objectAtIndex:index]];
}
}
NSLog(#"Print Mutable Copy %#",arrCopy);
try this one
NSArray *copyArray = [mainArray copy];
NSInteger index = [copyArray count] - 1;
for (id object in [copyArray reverseObjectEnumerator]) {
if ([mainArray indexOfObject:object inRange:NSMakeRange(0, index)] != NSNotFound) {
[mainArray removeObjectAtIndex:index];
}
index--;
}
copyArray=nil;

Grouping the NSArray elements into NSMutableDictionary

I have an NSArray some thing like in the following format.
The group array is :
(
"Q-1-A1",
"Q-1-A9",
"Q-2-A1",
"Q-2-A5",
"Q-3-A1",
"Q-3-A8",
"Q-4-A1",
"Q-4-A4",
"Q-10-A2",
"Q-8-A2",
"Q-9-A2",
"Q-7-A1",
"Q-5-A2"
)
Now what i have to do is group the array elements some thing like this.
1 = ( "Q-1-A1","Q-1-A9")
2 = ("Q-2-A1","Q-2-A5",) ...
10 =("Q-10-A2")
can any one please help me how can i achieve this.
Thanks in advance.
Try
NSArray *array = #[#"Q-1-A1",
#"Q-1-A9",
#"Q-2-A1",
#"Q-2-A5",
#"Q-3-A1",
#"Q-3-A8",
#"Q-4-A1",
#"Q-4-A4",
#"Q-10-A2",
#"Q-8-A2",
#"Q-9-A2",
#"Q-7-A1",
#"Q-5-A2"];
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
for (NSString *string in array) {
NSArray *components = [string componentsSeparatedByString:#"-"];
NSString *key = components[1];
NSMutableArray *tempArray = dictionary[key];
if (!tempArray) {
tempArray = [NSMutableArray array];
}
[tempArray addObject:string];
dictionary[key] = tempArray;
}
Create an NSMutableDictionary, then iterate through your 'group array'.
For each NSString object:
get the NSArray of componentsSeparatedByString:#"-"
use the second component to create a key and retrieve the object for that key from your mutable dictionary. If its nil then set it to an empty NSMutableArray.
add the original NSString to the mutable array.
Try this
NSArray *arrData =[[NSArray alloc]initWithObjects:#"Q-1-A1",#"Q-1-A9",#"Q-2-A1",#"Q-2-A5",#"Q-3-A1",#"Q-3-A8",#"Q-4-A1",#"Q-4-A4",#"Q-10-A2",#"Q-8-A2",#"Q-9-A2",#"Q-7-A1",#"Q-5-A2", nil ];
NSMutableDictionary *dictList = [[NSMutableDictionary alloc]init];
for (int i=0; i<[arrData count];i++) {
NSArray *arrItem = [[arrData objectAtIndex:i] componentsSeparatedByString:#"-"];
NSMutableArray *arrSplitedItems = [dictList valueForKey:[arrItem objectAtIndex:1]];
if (!arrSplitedItems) {
arrSplitedItems = [NSMutableArray array];
}
[arrSplitedItems addObject:[arrData objectAtIndex:i]];
[dictList setValue:arrSplitedItems forKey:[arrItem objectAtIndex:1]];
}
NSArray *sortedKeys =[dictList allKeys];
NSArray *sortedArray = [sortedKeys sortedArrayUsingComparator:^(id str1, id str2) {
return [((NSString *)str1) compare:((NSString *)str2) options:NSNumericSearch];
}];
for (int i=0; i<[sortedArray count]; i++) {
NSLog(#"%#",[dictList objectForKey:[sortedArray objectAtIndex:i]]);
}
listOfYourMainArray/// Its YOur main Array;
temArray = (NSArray *)listOfYourMainArray; // Add Your main array to `temArray`.
NSMutableDictionary *lastDic = [[NSMutableDictionary alloc] init]; /// YOu need to creat Dictionary for arrange your values.
for (int i = 0; i< listOfYourMainArray.count; i++)
{
for (int j = 0 ; j < temArray.count; j ++)
{
if (([[temArray objectAtIndex:j] rangeOfString:[NSString stringWithFormat:#"Q-%d", i] options:NSCaseInsensitiveSearch].location != NSNotFound))
{
[lastDic setValue:[temArray objectAtIndex:j] forKey:[NSString stringWithFormat:#"%d", i]];
}
}
}
NSLog(#"%#", lastDic)

better way of removing double (NSManagedObjects) from NSArray (also logic flaw)

I made the following method to remove doubles, however it doesn't fully work. Any suggestions?
Thank you for the help,
-(NSMutableArray*)removeDuplicateCars:(NSMutableArray*)array{
NSMutableArray *noDuplicates =[[NSMutableArray alloc]init];
for (int i=0; i<[array count]; i++) {
int counter =0;
Car *car =(Car*)[array objectAtIndex:i];
if ([noDuplicates count]==0) {
[noDuplicates addObject:car];
}
for (int i=0; i<[noDuplicates count]; i++) {
Car *car2 =(Car*)[array objectAtIndex:i];
if (![car.name isEqualToString:car2.name]) {
counter++;
}
}
if (counter==[noDuplicates count]) {
[noDuplicates addObject:car];
}
}
NSLog(#"number of results = %i",[noDuplicates count]);
return noDuplicates;
}
Create an array called "addedCars" - you will use it to store the name of each unique car.
In each iteration, use [NSArray containsObject:] to check if the current name has already been added to "addedCars". If not, add the name to "addedCars" and the car to "noDuplicates". Otherwise, skip this item, as it has already been added to noDuplicates.
be sure [isEqual:] and [hash] is implemented as you expected
-(NSMutableArray*)removeDuplicateCars:(NSMutableArray*)array{
NSOrderedSet *set = [[NSOrderedSet alloc] initWithArray:array];
NSMutableArray *newArr = [NSMutableArray arrayWithCapacity:[set count]];
for (id obj in set) {
[newArr addObject:obj];
}
return newArr;
}
You used ![car.name isEqualToString:car2.name] to compare objects so I believe you want to filter objects with same name? Than you need to override [isEqual:] for Car
- (BOOL)isEqual:(id)other {
if ([other isKindOfClass:[self class]]) {
return [self.name isEuqalToString: [other name]];
}
return NO;
}
- (NSUInteger)hash {
return [self.name hash];
}
also check this question The best way to remove duplicate values from NSMutableArray in Objective-C?

Resources