Count in multi-dimensional array - ios

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

Related

How to reference an array from another function Objective-C

I have declared array in SomeClass.h It's a global variable isn't it?
#property (nonnull, nonatomic, retain) NSMutableArray *additional_tabs;
Below I declared 2 function where I use this array.
- (id _Nullable)initFromJSON:(NSDictionary *_Nullable)dictionary;
- (void)moreTabs:(NSMutableArray *_Nullable)a;
Below is if-statement I used inside initFromJSON function.
if ([Tools isNonullValueForKey:[dictionary valueForKey:#"additional_tabs"]]) {
_additional_tabs = [NSMutableArray new]; //really I need them?
_additional_tabs = [dictionary valueForKey:#"additional_tabs"];
NSLog(#"additionalTabCount (initJSON) = %lu", [_additional_tabs count]);
for (int i = 0; i < [_additional_tabs count]; i++) {
if ([Tools isNonullValueForKey:[_additional_tabs valueForKey:#"_id"]]) {
_additional_tab_id = [[_additional_tabs valueForKey:#"_id"] objectAtIndex:i];
}
if ([Tools isNonullValueForKey:[_additional_tabs valueForKey:#"names"]]) {
NSDictionary *dic = [[_additional_tabs valueForKey:#"names"] objectAtIndex:i];
_en_additional_tab_name = [dic valueForKey:#"en"];
_pl_additional_tab_name = [dic valueForKey:#"pl"];
}
if ([Tools isNonullValueForKey:[_additional_tabs valueForKey:#"url"]]) {
_additional_tab_url = [[_additional_tabs valueForKey:#"url"] objectAtIndex:i];
}
NSLog(#"%# %d %# %# %# %#", #"pos", i, #"id: ", _additional_tab_id, #"url: ", _additional_tab_url);
}
}
And this [_additional_tabs count] have 17.
But in function moreTabs:
NSLog(#"additional tabs count: %lu",[_additional_tabs count]);
for (int i = 1; i < [_additional_tabs count]; i++) {
[a addObject:[[VCTab alloc] initWithIdAndTypeAndUrl:[[_additional_tabs valueForKey:#"_id"] objectAtIndex:i] :VCTabAdditional :[[_additional_tabs valueForKey:#"url"] objectAtIndex:i]]];
}
}
return [_additional_tabs count] with nil... look like is different array or cleared?
I would be very grateful for your help :)
All the best

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;

NSMutableArray (1 dim) from NSArray (2dim)

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.

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)

Resources