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
Related
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
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
So, I was tasked with randomizing a multidimensional array in Objective-C.
I needed to make this:
[[1,2,3],[4,5,6],[7,8,9],[10,11,12]]
Look something like this:
[[4,8,6],[1,7,9],[2,11,10],[3,5,12]]
I did that by hand, so please excuse me for the poor randomization.
This is what I came up with, please feel free to critique or improve it. I borrowed certain parts from existing SO contributions.
-(NSMutableArray *)shuffleArray:(NSMutableArray *)array
{
NSMutableArray *flatArray = [array valueForKeyPath:#"#unionOfArrays.self"];
NSUInteger count = flatArray.count;
for (NSUInteger i = 0; i < count; i++) {
NSInteger remainingCount = count - i;
NSInteger exchangeIndex = i + arc4random_uniform((u_int32_t)remainingCount);
[flatArray exchangeObjectAtIndex:i withObjectAtIndex:exchangeIndex];
}
NSMutableArray *set = [[NSMutableArray alloc] init];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
for (int i = 0; i < flatArray.count; i++) {
[tempArray addObject:flatArray[i]];
if ((i + 1) % 3 == 0) {
[set addObject:[tempArray copy]];
[tempArray removeAllObjects];
}
}
return set;
}
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.
I have an array of custom objects. The objects represent segments in a binary file.
The property loc holds the objects own location in the file, where prev holds the location of the "previous" object. In this context "previous" and "next" doesn't necessarily mean that the objects occur after each other in the file.
The first object has prev = 0. The last object has no following object holding its location as prev.
How do I achieve such kind of sorting? Number of objects is initially not known.
//My custom object
#interface MyObject : NSObject
#property (nonatomic, assign) NSInteger loc, prev;
#end
//In the implementation of some other class
NSMutableArray *array = [NSMutableArray new];
{// order should be 6
MyObject *obj = [MyObject new];
obj.loc = 3000;
obj.prev = 111;
[array addObject:obj];
}
{// order should be 2
MyObject *obj = [MyObject new];
obj.loc = 2000;
obj.prev = 222;
[array addObject:obj];
}
{// order should be 4
MyObject *obj = [MyObject new];
obj.loc = 333;
obj.prev = 4000;
[array addObject:obj];
}
{// order should be 1
MyObject *obj = [MyObject new];
obj.loc = 222;
obj.prev = 5000;
[array addObject:obj];
}
{// order should be 5
MyObject *obj = [MyObject new];
obj.loc = 111;
obj.prev = 333;
[array addObject:obj];
}
{// order should be 3
MyObject *obj = [MyObject new];
obj.loc = 4000;
obj.prev = 2000;
[array addObject:obj];
}
{// order should be 0
MyObject *obj = [MyObject new];
obj.loc = 5000;
obj.prev = 0;
[array addObject:obj];
}
Try using lexicographical sorting:
NSArray *sorted = [array sortedArayUsingComparator:^(id obj1, id obj2) {
if ([obj1 parentID] < [obj2 parentID] {
return NSOrderedAscending;
} else if ([obj1 parentID] > [obj2 parentID] {
return NSOrderedDescending;
} else if ([obj1 ID] < [obj2 ID] {
return NSOrderedAscending;
} else if ([obj1 ID] > [obj2 ID] {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}];
Never mind, I got it.
NSMutableArray *unordered = [[NSMutableArray alloc] initWithArray:array];
NSMutableArray *ordered = [NSMutableArray new];
for(MyObject *myObj in array)
{
if(!myObj.prev)
{
[orderedTables addObject:myObj];
[unorderedTables removeObject:myObj];
break;
}
}
int counter = 0;
while(unordered.count && counter < ordered.count)
{
MyObject *obj1 = [ordered objectAtIndex:counter++];
for(int i = 0; i < unordered.count; ++i)
{
MyObj *obj2 = [unordered objectAtIndex:i];
if(obj2.prev == obj1.loc)
{
[ordered addObject:obj2];
[unordered removeObject:obj2];
break;
}
}
}