I have an NSMutableArray of custom objects. Each contains an ID string that is unique, and each contains an downloadedDate property.
Objects could get added twice so I need to check the ID for duplicates, and if I find a duplicate I need to keep the one that has the newest date.
Currently I am doing the following to remove duplicates, but it doesn't take into account keeping the object with the newest date.
NSArray *originalArray = [NSArray arrayWithArray:mutableItems];
NSMutableArray *uniqueArray = [NSMutableArray array];
NSMutableSet *names = [NSMutableSet set];
for (ZSSObject *g in originalArray) {
NSString *destinationName = g.code;
if (![names containsObject:destinationName]) {
[uniqueArray addObject:g];
[names addObject:destinationName];
}
}
NSArray *uniqueObjects = uniqueArray;
Objects get created like this:
ZSSObject *obj = [ZSSObject alloc] init];
obj.code = #"12345";
obj.downloadedDate = [NSDate date];
Is there an easier way to do that I want than having a bunch of copies of my array and nested loops?
Using the suggestion to use an NSDictionary instead, I came up with this solution:
NSMutableDictionary *objDict = [[NSMutableDictionary alloc] init];
for (ZSSObject *g in mutableItems) {
ZSSObject *addedObj = objDict[g.code];
if (addedObj) {
// Compare dates
if ([addedObj respondsToSelector:#selector(dateDownloaded)]) {
if ([g.dateDownloaded compare:addedObj.dateDownloaded] == NSOrderedDescending) {
[objDict setObject:g forKey:g.code];
}
}
} else {
[objDict setObject:g forKey:g.code];
}
}
NSArray *uniqueObj = objDict.allValues;
I have made a quiz using Obj.C. What I want to to do is make the questions appear in random order. I have tried many methods but so far I have failed.
+ (NSArray *) myArray
{
static NSArray *theArray;
if (!theArray)
{
theArray = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:0], nil];
}
return theArray;
}
+ (NSArray *) questions {
return #[
#{#"question":
Here's how I generate a random array from another array.
NSArray *myArray = #[object1, object2, object3, ..., objectN];
NSMutableArray *arrayToTakeItemsFrom = [[NSMutableArray alloc] arrayWithArray:myArray];
NSMutableArray *randomOrderedArray = [NSMutableArray new];
while (arrayToTakeItemsFrom.count > 0) {
int randomIndex = arc4random_uniform(arrayToTakeItemsFrom.count);
MyObjectClass *swapObject = [arrayToTakeItemsFrom objectAtIndex:randomIndex];
[arrayToTakeItemsFrom removeObject:swapObject];
[randomOrderedArray addObject:swapObject];
}
//Now randomOrderedArray has everything myArray has in it but in a random order, and always works for any size array including an empty array
I have created a plist file that looks like this:
From this is am able to extract all plist info into an NSArray:
-(NSArray *)Topics
{
if(!_Topics)
{
_Topics = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"TopicData" ofType:#"plist"]];
}
return _Topics;
}
And use this array to load a tableview of TopicTitle's:
cell.textLabel.text = [[self.Topics objectAtIndex:indexPath.row] valueForKey:#"TopicTitle"];
When a row in the table is selected, I am passing the dictionary named 'Questions' to the next ViewController like this:
NSDictionary *questions = [[self.Topics objectAtIndex:indexPath.row] valueForKey:#"Questions"];
[self.detailViewController setQuestions:(questions)];
From here I want to loop through each 'Question' dictionary and load the 'QuestionText' and 'AnswerOne / Two...' strings into an array of objects by doing something like this:
TopicQuestions = [NSMutableArray array];
for(NSDictionary *ques in self.Questions)
{
Question* q = [[Question alloc] init];
q.Question = (NSString*)[ques objectForKey:#"QuestionText"];
q.AnswerOne = (NSString*)[ques objectForKey:#"QuestionText"];
q.AnswerTwo = (NSString*)[ques objectForKey:#"QuestionText"];
q.AnswerThree = (NSString*)[ques objectForKey:#"QuestionText"];
q.AnswerFour = (NSString*)[ques objectForKey:#"QuestionText"];
[TopicQuestions addObject:q];
}
But the 'Questions' dictionary does not seem to have this data available, it knows there are 4 child objects, but does not have all the key - pair values of these objects:
So my question is how should I pass the 'Questions' dictionary to the next ViewController so that I will still be able to access the 'QuestionText' and 'AnswerOne / Two...' nodes?
Or is there a better way of reading the strings without looping through each 'Question' dictionary?
I don't think you are getting the question dictionary properly. In your screenshot the ques object is an NSString object, not an NSDictionary. So getting objectForKey on the NSString object ques is not going to work (and really should crash your app).
Try this for loop:
for(NSString *ques in self.Questions)
{
NSDictionary *dict = [self.questions objectForKey:ques];
Question* q = [[Question alloc] init];
q.Question = (NSString*)[dict objectForKey:#"QuestionText"];
q.AnswerOne = (NSString*)[dict objectForKey:#"QuestionText"];
q.AnswerTwo = (NSString*)[dict objectForKey:#"QuestionText"];
q.AnswerThree = (NSString*)[dict objectForKey:#"QuestionText"];
q.AnswerFour = (NSString*)[dict objectForKey:#"QuestionText"];
[TopicQuestions addObject:q];
}
We have an app that calls a SOAP web service and retrieves a long list of XML, which the app then parses into an NSArray of NSDictionary objects. The NSArray contains a list of Rental Apartment information, each of which is stored into an NSDictionary.
The entire list may contain 10 different types of Apartments (i.e. 2-room, 3-room), and we need to split the NSArray into smaller NSArrays based on Room-Type, which has the key "roomType" in the NSDictionary objects.
Currently our algorithm is
Use [NSArray valueForKeyPath:#"#distinctUnionofObjects.room-type"]
to obtain a list of unique room-type values.
Loop through the list of unique room-type values
For each unique room-type value, use NSPredicate to retrieve matching items from the Original list
Our code is below (renamed for clarity):
NSArray *arrOriginal = ... ...; // Contains the Parsed XML list
NSMutableArray *marrApartmentsByRoomType = [NSMutableArray arrayWithCapacity:10];
NSMutableArray *arrRoomTypes = [arrOriginal valueForKeyPath:#"distinctUnionOfObjects.roomType"];
for(NSString *strRoomType in arrRoomTypes) {
NSPredicate *predicateRoomType = [NSPredicate predicateWithFormat:#"roomType=%#", strRoomType];
NSArray *arrApartmentsThatMatchRoomType = [arrOriginal filteredArrayUsingPredicate:predicateRoomType]; // TAKES A LONG TIME EACH LOOP-ROUND
[marrApartmentsByRoomType addObject:arrApartmentsThatMatchRoomType];
}
However, step 3 is taking a long time as the original list may contain large amount (>100,000) of items. It seems that NSPredicate goes through the entire list for each key value. Is there a more efficient way of splitting a large NSArray into smaller NSArrays, based on NSDictionary keys?
If the order of your splited Arrays is not important, i have a solution for you:
NSArray *arrOriginal;
NSMutableDictionary *grouped = [[NSMutableDictionary alloc] initWithCapacity:arrOriginal.count];
for (NSDictionary *dict in arrOriginal) {
id key = [dict valueForKey:#"roomType"];
NSMutableArray *tmp = [grouped objectForKey:key];
if (tmp == nil) {
tmp = [[NSMutableArray alloc] init];
[grouped setObject:tmp forKey:key];
}
[tmp addObject:dict];
}
NSMutableArray *marrApartmentsByRoomType = [grouped allValues];
This is quite performant
- (NSDictionary *)groupObjectsInArray:(NSArray *)array byKey:(id <NSCopying> (^)(id item))keyForItemBlock
{
NSMutableDictionary *groupedItems = [NSMutableDictionary new];
for (id item in array) {
id <NSCopying> key = keyForItemBlock(item);
NSParameterAssert(key);
NSMutableArray *arrayForKey = groupedItems[key];
if (arrayForKey == nil) {
arrayForKey = [NSMutableArray new];
groupedItems[key] = arrayForKey;
}
[arrayForKey addObject:item];
}
return groupedItems;
}
Improving #Jonathan answer
Converting array to dictionary
Maintaining the same order as it was in original array
//only to a take unique keys. (key order should be maintained)
NSMutableArray *aMutableArray = [[NSMutableArray alloc]init];
NSMutableDictionary *dictFromArray = [NSMutableDictionary dictionary];
for (NSDictionary *eachDict in arrOriginal) {
//Collecting all unique key in order of initial array
NSString *eachKey = [eachDict objectForKey:#"roomType"];
if (![aMutableArray containsObject:eachKey]) {
[aMutableArray addObject:eachKey];
}
NSMutableArray *tmp = [grouped objectForKey:key];
tmp = [dictFromArray objectForKey:eachKey];
if (!tmp) {
tmp = [NSMutableArray array];
[dictFromArray setObject:tmp forKey:eachKey];
}
[tmp addObject:eachDict];
}
//NSLog(#"dictFromArray %#",dictFromArray);
//NSLog(#"Unique Keys :: %#",aMutableArray);
//Converting from dictionary to array again...
self.finalArray = [[NSMutableArray alloc]init];
for (NSString *uniqueKey in aMutableArray) {
NSDictionary *aUniqueKeyDict = #{#"groupKey":uniqueKey,#"featureValues":[dictFromArray objectForKey:uniqueKey]};
[self.finalArray addObject:aUniqueKeyDict];
}
Hope, It will help when client wants final array in same order as input array.
I am new to iOS and want to create an NSArray like this which contains an NSDictionary.
[
{
Image: 1, 2,3
Title: 1,2,3
Subtitle:1,2,3
}
]
I have tried this.
NSArray *obj-image=#[#"Test.png",#"Test.png",#"Test.png"];
NSArray *obj-title=#[#"Test",#"Test",#"Test"];
NSArray *obj-subtitle=#[#"Test",#"Test",#"Test"];
NSDictionary * obj_dictionary ={ image : obj_image, title:obj_title, subtitle:obj_subtitle}
NSArray * obj_array= [obj_dictionarry];
But not working and how to access them.
First of all, you initialization of Arrays and Dictionaries is wrong. You cannot use "-" in the names, period.
Second, you need to allocate and then initialize the objects. This is how you do that with arrays:
NSArray *images = [NSArray arrayWithObjects: #"TestImage",#"TestImage",#"TestImage",nil];
NSArray *titles = [NSArray arrayWithObjects: #"TestTitle",#"TestTitle",#"TestTitle",nil];
NSArray *subtitles = [NSArray arrayWithObjects: #"TestSubTitle",#"TestSubTitle",#"TestSubTitle",nil];
Then you need Mutable dictionary and mutable arrays to work with the data (mutable means you can change the values inside, add or remove objects etc.)
This is the most basic example of what you are trying to achieve:
NSArray *images = [NSArray arrayWithObjects: #"TestImage",#"TestImage",#"TestImage",nil];
NSArray *titles = [NSArray arrayWithObjects: #"TestTitle",#"TestTitle",#"TestTitle",nil];
NSArray *subtitles = [NSArray arrayWithObjects: #"TestSubTitle",#"TestSubTitle",#"TestSubTitle",nil];
NSMutableArray *objectsMutable = [[NSMutableArray alloc] init];
for (NSString *string in images) {
NSMutableDictionary *dictMutable = [[NSMutableDictionary alloc] init];
[dictMutable setObject:string forKey:#"image"];
//determining the index of the image
NSInteger stringIndex = [images indexOfObject:string];
[dictMutable setObject:[titles objectAtIndex:stringIndex] forKey:#"title"];
[dictMutable setObject:[subtitles objectAtIndex:stringIndex] forKey:#"subtitle"];
NSDictionary *dict = [[NSDictionary alloc] init];
dict = dictMutable;
[objectsMutable addObject:dict];
}
NSArray *objects = objectsMutable;
NSLog(#"%#", objects);
Hope this helps.
As you can see, I'm going through the images array, capturing the index of each one, an then just apply values of other arrays from the same index into a mutable dictionary.
All I do after that is just make a regular dictionary and array to put the data inside. This is ho the Log will look:
(
{
image = TestImage;
subtitle = TestSubTitle;
title = TestTitle;
},
{
image = TestImage;
subtitle = TestSubTitle;
title = TestTitle;
},
{
image = TestImage;
subtitle = TestSubTitle;
title = TestTitle;
}
)
You have an array with three objects inside, each with their own image, title and subtitle.
Here is code :
NSMutableArray *array = [[NSMutableArray alloc] init];
NSMutableDictionary *mdict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"object1",#"key1",#"object2",#"key2",nil];
[array addObject:mDict];
so now if u need to access dictionary from array then :
NSMutableDictionary *mDict1 = [array objectatindex:0];
NSLog(#"%#",[mDict1 valueForkey:#"key1"];
--> print object 1.
This is the way to store array of dictionaries:
NSDictionary *dic=#{#"kishore":#"hai"};
NSMutableArray *arr=[[NSMutableArray alloc]init];
[arr addobject:dic];
this is the way to get those values:
[arr objectforkeyValue #"kishore"];
NSMutableArray *dictArray = [[NSMutableArray alloc] init]; // created and initiated mutable array
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; // created and initiated mutable Dictionary
[dict setObject:#"object1" forKey:#"1"]; // added a key pair in dictionary (you can set multiple objects)
[dictArray addObject:dict]; // added dictionary to array (you can add multiple dictionary to array )
NSLog(#"dictionary inside an array : %#",dictArray[0][#"1"]); // access dictionary from array
You can try something like this
[NSArray arrayWithObjects:#{#"Image":#[#1,#2,#3]},#{#"Title":#[#1,#2,#3]},#{#"SubTitle":#[#1,#2,#3]}, nil];
You can easily create objects of array and access them back using following way.
NSArray *objimage=#[#"Test1.png",#"Test2.png",#"Test3.png"];
NSArray *objtitle=#[#"Test1",#"Test2",#"Test3"];
NSArray *objsubtitle=#[#"Test1",#"Test2",#"Test3"];
NSDictionary *obj_dictionary = #{#"image":objimage,#"Title":objtitle, #"subtitle":objsubtitle};
NSArray * obj_array= [[NSArray alloc] initWithObjects:obj_dictionary, nil]; // Create Array of nested objects
if([obj_array count] > 0) {
NSArray * imageArray = obj_array[0][#"image"]; // Access the nested objects in Array.
NSLog(#"%#", imageArray[0]);
}
first of all u need to declare correct variable name
NSArray *objImage=#[#"Test.png",#"Test.png",#"Test.png"];
NSArray *objTitle=#[#"Test",#"Test",#"Test"];
NSArray *objSubtitle=#[#"Test",#"Test",#"Test"];
at this point all u are created all the array, and u need to create dictionary like below
NSDictionary *obj_dictionary = #{#"image":objImage,#"title":objTitle, #"subtitle":objSubtitle};
// NSArray * obj_array = obj_dictionary[#"image"];
NSArray * obj_array = #[obj_dictionary]; //u can crate array of dictionary like this
in above obj_dictionary will contains all the array like below,
Title = (
Test,
Test,
Test
);
image = (
"Test.png",
"Test.png",
"Test.png"
);
subtitle = (
Test,
Test,
Test
);
and u can access the object in the dictionary like below using a key for example
NSArray * obj_array_images = obj_dictionary[#"image"];
gives an array of images that is associated with key image, similarly u can access other array like this by providing different keys associated with the dictionary obj_dictionary for example
NSArray * obj_array_titles = obj_dictionary[#"title"];
NSArray * obj_array_subtitles = obj_dictionary[#"subtitle"];
edit
NSArray *objImage=#[#"Test.png",#"Test.png",#"Test.png"];
NSArray *objTitle=#[#"Test",#"Test",#"Test"];
NSArray *objSubtitle=#[#"Test",#"Test",#"Test"];
NSDictionary *obj_dictionary = #{#"image":objImage,#"title":objTitle, #"subtitle":objSubtitle};
// NSArray * obj_array = obj_dictionary[#"image"];
NSArray * obj_array = #[obj_dictionary]; //u can crate array of dictionary like this