I have an NSMutableArray(ArrayOne) structured like so..
({
"item_image_timeStamp" = "492364855.234597";
"item_image_url" = "sample url";
"item_image_vote" = 123;
}, {
"item_image_timeStamp" = "492364458.236597";
"item_image_url" = "sample url";
"item_image_vote" = 456;
}, {
"item_image_timeStamp" = "492364179.052397";
"item_image_url" = "sample url";
"item_image_vote" = 6184;
}, {
"item_image_timeStamp" = "492364789.004447";
"item_image_url" = "sample url";
"item_image_vote" = 64;
}, {
"item_image_timeStamp" = "492364356.002341";
"item_image_url" = "sample url";
"item_image_vote" = 3778;
})
The maximum number of objects that can be contained in ArrayOne is 10.
Then, I have a second NSMutableArray(ArrayTwo) structured just like ArrayOne
({
"item_image_timeStamp" = "492364855.234597";
"item_image_url" = "sample url";
"item_image_vote" = 123;
}, {
"item_image_timeStamp" = "492364458.236597";
"item_image_url" = "sample url";
"item_image_vote" = 456;
})
..except that the maximum number of objects that can be contained in ArrayTwo is 3.
Now, What I want to do is..
add objects of ArrayTwo into ArrayOne (keeping in mind that ArrayOne can only hold a maximum of 10 objects)
keep the top 5 objects sorted by the key "item_image_vote" (top five voted object should not be replaced)
if any objects in ArrayOne need to be replaced, item with the lowest value for key "item_image_timeStamp" should be replaced first.(oldest object will be replaced first..followed by the the second oldest).
I hope I did not make my question too confusing. Thank you in advance.
Adding, removing and measuring length are all methods on mutable arrays, straight-forward to apply. The interesting part of the question is the sort criteria, which is very well addressed by NSSortDescriptor.
NSArray allows the application of these in groups with sortedArrayUsingDescriptors (notice the plural). So a good approach is to add arrays, sort according to your criteria and truncate to a max length.
// sort on vote, descending
NSSortDescriptor *voteDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"item_image_vote" ascending:NO];
// sort on date, descending
NSSortDescriptor *dateDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"item_image_timeStamp" ascending:NO];
NSMutableArray *bigArray = [ArrayOne mutableCopy]; // note: lowercase variable names is considered preferable style
[bigArray addObjectsFromArray:ArrayTwo];
[bigArray sortUsingDescriptors:#[voteDescriptor, dateDescriptor]];
// note: order matters. you want votes sorted first, ties broken with date
The result is the bigArray, now sorted, truncated to the max size.
NSArray *result = [bigArray subarrayWithRange:NSMakeRange(0, MIN(10, bigArray.count))];
Yes..exactly what you said..the final array is meant to contain (a) the original top 5 from First, (b) all of Second, and (c) the youngest of any remains items in First that will fit
Just work through your requirement in steps:
If the number of items in First & Second combined is <= 10 just join.
"the original top 5 from First" - Sort First by vote count, you can use a function, block or descriptor based sort. Copy the first 5 (there must be at least 5 due to [1] so no checking required here) items to be your result.
"all of Second" - Append the elements of Second to your result. You now have 6-8 items in your result.
Copy items 6 onwards of your sorted First from [2] and sort the resulting array by age. Append the first 2-4 items, as needed, to your result.
All the above can be done with standard NSArray methods for sorting, copying and appending,
HTH
Related
submittedTestArray = [{
scheduledTestId = "F7F15169-2FB6-4E47-A971-BAAD40D152AB";
studentId = "8b3df16f-ff2f-4ad4-839c-6a937b79854d";
submittedTestId = "37F20871-FB3A-47AA-B254-9E5409C5E4C4";
}, {
scheduledTestId = "440947DD-0A01-4DB8-8DD5-CCFA8F852FD3";
studentId = "8b3df16f-ff2f-4ad4-839c-6a937b79854d";
submittedTestId = "681689DC-B35C-491C-A737-AB19D9116FD9";
}, {
scheduledTestId = "440947DD-0A01-4DB8-8DD5-CCFA8F852FD3";
studentId = "8b3df16f-ff2f-4ad4-839c-6a937b79854d";
submittedTestId = "681689DC-B35C-491C-A737-AB19D9116FD9";
}, {
scheduledTestId = "440947DD-0A01-4DB8-8DD5-CCFA8F852FD3";
studentId = "e18ead0a-d0fc-4e15-96ee-ecbd32880d97";
submittedTestId = "A46965C6-14B1-401E-97C5-AD5BADCC02EE";
}]
I want all the NSDictionary objects uniquely based on scheduledTestId
If i will consider above example then it will give me two NSDictionary objects.
Temporarily i am using following code.
NSMutableArray *uniqueKeys = [NSMutableArray arrayWithArray:[submittedTestArray valueForKeyPath:#"#distinctUnionOfObjects.scheduledTestId"]];
NSMutableArray *submittedTestUniqueArray = [[NSMutableArray alloc] initWithCapacity:uniqueKeys.count];
for (SubmittedTest *submittedTest in submittedTestArray) {
if ([uniqueKeys containsObject:submittedTest.scheduledTestId ]) {
[uniqueKeys removeObject:submittedTest.scheduledTestId];
[submittedTestUniqueArray addObject:submittedTest];
}
}
submittedTestUniqueArray is contain my desired output i.e.
[{
scheduledTestId = "F7F15169-2FB6-4E47-A971-BAAD40D152AB";
studentId = "8b3df16f-ff2f-4ad4-839c-6a937b79854d";
submittedTestId = "37F20871-FB3A-47AA-B254-9E5409C5E4C4";
}, {
scheduledTestId = "440947DD-0A01-4DB8-8DD5-CCFA8F852FD3";
studentId = "8b3df16f-ff2f-4ad4-839c-6a937b79854d";
submittedTestId = "681689DC-B35C-491C-A737-AB19D9116FD9";
}]
Instead of for-in loop, go with a for loop and after iterating each time
if ([uniqueKeys containsObject:submittedTest.scheduledTestId ]) {
[uniqueKeys removeObject:submittedTest.scheduledTestId];
}
else
{
[submittedTestArray removeObjectAtIndex:currentIndex];
}
I dont know what I am writing is up-to the mark but still I am daring to answer.
Ideally what you have tried is perfect. Coz to remove duplicate records from the dictionary, there is a need to have a bunch of records, in this case
an array named uniqueKeys with scheduledTestId values, to compare each dictionary element with all other elements for duplication.
And this is what exactly you have done.
The only improvements I can suggest in this code is instead of NSMutableArray *uniqueKeys
change it to NSArray *uniqueKeys; and after finishing the comparison & collecting the dictionary objects with the unique records, flush the array elements instead of removing them one by one.
Coz having 2 mutable arrays, one having simply unique keys & other having dictionary objects with unique records doesn't make any sense. Of course I presume that you dont need an array with only unique keys. What you need is dictionary not an array, right?
So in short I dont find any performance improvements in your code.
#ALL: Please let me know if there are any improvements in my technical knowledge.
CHEERS HAPPY CODING
I am very new to programming in Objective C (as in a few days), and unfortunately have an iPhone app due as a project for a class in a few days (in retrospect I probably should have chosen something different). One of the main features my app needs is the ability to select a dish from a menu by first selecting the meal on one page, and then the category on the next page, and then the dish on the final page. I have gotten my app to download a JSON file from an internet API and store it as an NSArray variable, but now I need to use that array to populate my tableview. Below is a sample from the downloaded array from my app's debug window. I already have the basic framework of the app (i.e. several different views) in place. This came from a sample app that populates the tableview rows with data from a plist file, but I want to use this JSON data. How would I use this array to populate the rows with the JSON data stored in this NSArray variable?
Thanks!
2012-12-05 03:29:48.973 MLBMobile[3858:c07] {
category = "BREAKFAST MEATS";
date = "2012-12-05";
meal = BREAKFAST;
name = "Low-Sodium Ham";
portion = 1;
recipe = 319044;
unit = oz;
}
2012-12-05 03:29:48.975 MLBMobile[3858:c07] {
category = "BREAKFAST MEATS";
date = "2012-12-05";
meal = BREAKFAST;
name = "Roasted Low-Sodium Turkey";
portion = 4;
recipe = 113503;
unit = oz;
}
2012-12-05 03:29:48.976 MLBMobile[3858:c07] {
category = "BREAKFAST ENTREES";
date = "2012-12-05";
meal = BREAKFAST;
name = "Cheddar Cheese";
portion = 1;
recipe = 130029;
unit = oz;
}
2012-12-05 03:29:48.976 MLBMobile[3858:c07] {
category = "BREAKFAST ENTREES";
date = "2012-12-05";
meal = BREAKFAST;
name = "Hard Cooked Eggs - Cage Free";
portion = 1;
recipe = 061009;
unit = each;
}
With your array variable you can iterate through each element. Use fast enumeration:
for(NSDictionary *dict in yourArrayVariable){
NSString *category = [dict objectForKey:#"name"];
//...you get the point
}
Now you can populate your row by just setting the properties of the row. For example, if you are using the default UITableViewCell:
cell.textLabel.text = name;
There is a bit more to this that you can do for better data/model/view separation, but I have just included examples as if it were all done locally in one file.
In my iPhone app.
I am copying the one mutable array(with dictionary) to another.
It is like
resultsToDisplay = [[[NSMutableArray alloc]initWithArray:resultsPassed]mutableCopy];
2012-06-21 17:07:07.441 AllinoneCalc[3344:f803] Results To Display (
{
lbl = "Monthly EMI";
result = "75.51";
}
)
2012-06-21 17:07:08.224 AllinoneCalc[3344:f803] Results Passed (
{
lbl = "Monthly EMI";
result = "75.51";
}
)
Then I am modifying one of them .
[[resultsToDisplay objectAtIndex:i] setValue:[NSString stringWithFormat:#"%.2f",[[[resultsPassed objectAtIndex:i] valueForKey:#"result"] floatValue]] forKey:#"result"];
But what is happening that both are getting edited.
2012-06-21 17:07:08.703 AllinoneCalc[3344:f803] Results Passed (
{
lbl = "Monthly EMI";
result = "75.00";
}
)
2012-06-21 17:07:08.705 AllinoneCalc[3344:f803] Results To Display (
{
lbl = "Monthly EMI";
result = "75.00";
}
)
They both are referring to the same copy.
How to solve this. I want to modify only one array.
You are only copying the array of object pointers, not the object themself. See this article on deep copying.
an array (or mutable array) is just a list of objects, and you are modifing one of the objects referred in one of your array. the second array is still pointing to the same object, so it's normal that it changes too...
you are copying the array: meaning you're copying the list of objects, not copying all the objects in list.
I am working on an application for the iPhone in which I want to get a start and end date for a Zodiac sign to display on the label. I am not sure how to store this info. I was thinking to store it in Core Data but that could be slow traversing it every time. My other idea is to have a NSDictionary of arrays for each sign. For example
self.zodiacSignsDates = [[NSDictionary alloc]initWithObjectsAndKeys:
[NSArray arrayWithObjects:#"December 22",#"January 20",nil], #"Capricorn",
[NSArray arrayWithObjects:#"January 21", #"February 18",nil], #"Aquarius"
,nil];
I might also use this NSDictionary later on to figure out zodiac sign for a birth date.
Please let me know what you think on on how to storing such data
Thanks!
Posting this as an answer, because of many comments. In addition: wouldn't it be enough to just store the last day of the period in an array the same length as the zodiacs?
var signs = ["Capricorn","Aquarius", ... ];
var lastDay = ["01-20", "02-18", ... ];
last one, i promise. if you want to keep those english strings, you could do this:
(since I assume, you already have a list of zodiacs around)
var dates = [["December 22","January 20"],["January 21","February 18"],[etc,etc] ];
and then
private String[] getFromTo( string zodiac ){
var idx = signs.indexOf(zodiac);
return dates[idx];
}
I have a NSDictionary, which looks like:
0 = {
content = Test;
date = "2012-02-02 18:36:46 +0000";
};
1 = {
content = "#### da ####";
date = "2012-02-02 18:36:46 +0000";
};
2 = {
content = dfdffdfddfdffddf;
date = "2012-02-03 20:30:31 +0000";
};
But if I delete the second key (number 1 in the example) the dictionary ends up like:
0 = {
content = Test;
date = "2012-02-02 18:36:46 +0000";
};
2 = {
content = dfdffdfddfdffddf;
date = "2012-02-03 20:30:31 +0000";
};
How could I reorganizate them so it maintains the order (like 0, 1, 2, 3) when I need to?
NSDictionaries are unordered, meaning that you cannot control the order of keys and they may change randomly or in undocumented ways between iOS versions.
You have a few options:
Maintain your own, separate NSArray of keys, and use that to index your dictionary.
Use this OrderedDictionary class that I wrote, which basically does that but wraps it all up in an NSDictionary subclass so you don't have to do any extra work:
http://charcoaldesign.co.uk/source/cocoa#ordered-dictionary
If your dictionary keys are numbers (or if they are alphabetical, or something else that's easy to sort automatically), you could just sort the keys whenever you need to display them in order using:
NSArray *keys = [dict allKeys];
keys = [keys sortedArrayUsingSelector:#selector(compare:)];
//now loop over keys array instead of directly over dictionary