Sequentially ordered NSMutableArray - replacing breaks in order - ios

I've been having a mind blank over this problem, so I thought maybe some of you could shed a light on the situation.
To cut a long story short, I am building an app that fetches a school student's timetable from a server, parses it, and displays it in a table view. Each student has 7 periods per day, and there are 10 days in the timetable spanning across a fortnight (5 days in Week A, 5 days in Week B).
However the problem lies where some students have free periods - that is, they do not have a class during that period. Because the server does not take free periods into account, some students might return 70 total periods in the fortnight, whereas another might return 66.
Cutting to the chase here...
I have an ordered NSMutableArray full of NSDictionaries. A typical object in the array would look like this when outputted to the console:
{
weekday = 12;
period = 1;
room = "Room D404";
title = "English Extension";
},
I need to figure out where there is a break in the order, and if so, insert an object into it to fill the blank. Let me give you an example:
{
dayweek = 12;
period = 1;
room = "Room D404";
title = "English Extension";
},
{
dayweek = 12;
period = 2;
room = "Room W285";
title = "Modern History";
},
{
dayweek = 12;
period = 3;
room = "Room W187";
title = "Maths Extension 1";
},
{
dayweek = 12;
period = 4;
room = "Room W370";
title = Economics;
},
{
dayweek = 12;
period = 6;
room = "Room D301";
title = "English Advanced";
},
{
dayweek = 12;
period = 7;
room = "Room W282";
title = "Studies of Religion";
},
{
dayweek = 13;
period = 1;
room = "Room W370";
title = Economics;
},
There is no object where period = 5, so I need to add one. Is what I'm saying hard to understand? Sorry if it is.
Thanks in advance!

This fills in missing periods from 1 to the last existing on a day. It does not fill days to a given minimum of periods.
NSMutableArray periods; // from somewhere else
NSUInteger count = [periods count];
NSUInteger currentPeriod = 0;
NSUInteger currentDayweek = 0;
for (NSUInteger i = 0; i < count; ++i)
{
NSDictionary *periodDescription = periods[i];
NSUInteger dayweek = [periodDescription[#"dayweek"] unsignedIntegerValue];
if (dayweek != currentDayweek) {
// another day
currentPeriod = 0;
currentDayweek = dayweek;
}
NSUInteger period = [periodDescription[#"period"] unsignedIntegerValue];
currentPeriod += 1;
while (period > currentPeriod) {
NSDictionary *fillIn = #{ #"dayweek" : #(dayweek), #"period" : #(currentPeriod), #"room" : #"cafeteria", #"title" = "taking a break" };
[periods insertObject:fillIn atIndex:i];
currentPeriod += 1;
i += 1;
count += 1;
}
}
If you do not want to fill morning hours before the first existing period, add this directly before the while loop:
if (currentPeriod == 1)
currentPeriod = period;
Note: Typed in browser, errors are probable.

Try this and let me know if you are getting any issues
for (int i = 1; i<=self.arrayForRows.count; i++)
{
if ([[[self.arrayForRows objectAtIndex:i]valueForKey:#"period"] intValue] == i)
{
}
else
{
// Insert Here as [self.arrayForRows insertObject:yourObject atIndex:i];
i=i-1;
}
}

This is only a partial answer, but too long to post as a comment.
The purpose of this snippet is only to identify missing periods with a minimal amount of code. You would need to do it in a loop for all days of the fortnight, of course.
To do this you can use predicates:
// For each day create a list of all periods.
// This is just a hard coded example
NSArray *allPeriodsForDay = #[#(1),#(2),#(3),#(4),#(5),#(6)];
// Get an array of the periods actually in the list
// It will look like this: #[#(1),#(2),#(4),#(5),#(6)]; // Period 3 missing
NSArray *studentsPeriods = [periodRecords valueForKey: #"period"];
// Build a predicate to identify period(s) not in list
NSPredicate *freePredicate = [NSPredicate predicateWithFormat:#"not self in %#", studentsPeriods];
NSArray *freePeriods = [allPeriodsForDay filteredArrayUsingPredicate:freePredicate];
freePeriods now contains a list of the "missing" periods in the students' schedule for that day.
You can then create a new NSDictionary and add it to the list. Then sort it all by the period field.

Related

Parsing JSON with NSDictionary

I am working on an app which fetches data from a server. I convert this data to XML and then parse it using XMLDictionary. My problem is counting the number of objects inside the dictionary.
"finance_fee_collection" = (
{
amount = "790.00";
"due_date" = "2015-06-04";
name = "Third Payment";
},
{
amount = "790.00";
"due_date" = "2014-12-11";
name = "First Payment";
},
{
amount = "740.00";
"due_date" = "2015-07-06";
name = "third payment";
}
);
Counting the above number of objects yields 3, which is true. But counting the following also results 3.
"finance_fee_collection" = {
amount = "740.00";
"due_date" = "2015-07-06";
name = "third payment";
};
What I want is to count the number of "finance_fee_collection" items, such that the first one results 3 and the second one results 1. Is there anyway I can approach this goal?
The first one seems to be an array, the second a dictionary:
if([finance_fee_collection iskindOfClass:[NSDictionary class]]){
count = 1;
} else {
count = result.count;
}
something similar to this should work. :) hope it is helpful.
This doesn't make sense really, since both NSArray and NSDictionary implement the count method, which should return 3 for both structures:
id obj = #[#1 ,#2, #3]; // This is an NSArray
NSLog(#"%lu", (unsigned long)[obj count]); // Outputs 3
obj = #{ #1:#1,
#2:#2,
#3:#3
}; // now it's an NSDictionary
NSLog(#"%lu", (unsigned long)[obj count]); // Outputs 3
Were you using [object count] to get the count?
Either way, I wouldn't assume that count would be 1 simply because the data structure is a dictionary (you didn't count it)

Access Nested NSDictionary Items

I have this NSDictionary that i received from an api call:
{
items = (
{
accessInfo = {
accessViewStatus = SAMPLE;
country = US;
embeddable = 1;
epub = {
isAvailable = 0;
};
pdf = {
isAvailable = 0;
};
publicDomain = 0;
quoteSharingAllowed = 0;
textToSpeechPermission = ALLOWED;
viewability = PARTIAL;
webReaderLink = "http://books.google.com/books/reader?id=LdB2_WzYpKgC&hl=&printsec=frontcover&output=reader&source=gbs_api";
};
etag = 1xxAlevFUSc;
id = "LdB2_WzYpKgC";
kind = "books#volume";
saleInfo = {
country = US;
isEbook = 0;
saleability = "NOT_FOR_SALE";
};
searchInfo = {
textSnippet = "The saga of their daily exploits won cartoonist Bill Watterson the coveted Reuben Award for "Outstanding Cartoonist of the Year." Something Under the Bed Is Drooling is a jewel.";
};
selfLink = "https://www.googleapis.com/books/v1/volumes/LdB2_WzYpKgC";
volumeInfo = {
authors = (
"Bill Watterson"
);
averageRating = "4.5";
canonicalVolumeLink = "http://books.google.com/books/about/Something_Under_the_Bed_Is_Drooling.html?hl=&id=LdB2_WzYpKgC";
categories = (
Humor
);
contentVersion = "0.0.1.0.preview.1";
description = "\"Be good to yourself: Buy a copy of this Calvin and Hobbes cartoon book. If you don't laugh out loud at every third strip, check your pulse. You may be dead.\" --Phil Musick, Pittsburgh Press Calvin is a rambunctious six-year-old whose manic antics threaten world peace. Hobbes is his stuffed tiger who comes alive when adults aren\"t around. The saga of their daily exploits won cartoonist Bill Watterson the coveted Reuben Award for \"Outstanding Cartoonist of the Year.\" Something Under the Bed Is Drooling is a jewel.";
imageLinks = {
smallThumbnail = "http://bks8.books.google.com/books?id=LdB2_WzYpKgC&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api";
thumbnail = "http://bks8.books.google.com/books?id=LdB2_WzYpKgC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api";
};
industryIdentifiers = (
{
identifier = 0836218256;
type = "ISBN_10";
},
{
identifier = 9780836218251;
type = "ISBN_13";
}
);
infoLink = "http://books.google.com/books?id=LdB2_WzYpKgC&dq=isbn:0836218256&hl=&source=gbs_api";
language = en;
pageCount = 127;
previewLink = "http://books.google.com/books?id=LdB2_WzYpKgC&printsec=frontcover&dq=isbn:0836218256&hl=&cd=1&source=gbs_api";
printType = BOOK;
publishedDate = "1988-01-01";
publisher = "Andrews McMeel Publishing";
ratingsCount = 18;
readingModes = {
image = 1;
text = 0;
};
title = "Something Under the Bed Is Drooling";
};
}
);
kind = "books#volumes";
totalItems = 1;
}
What I want to do is create an object from the items in this dictionary. This method needs to work generically for all books without crashing. Even if they are missing some of the attributes. The attributes I need to extract are:
-authors last name (Need for every author listed if there is more than one)
-authors first name (Need for every author listed if there is more than one)
-title
-description
-smallThumbnail
-thumbnail
-isbn_10 identifier
-category
From these I am going to create a "book" object. i will also create an NSSet of Authors, and each Author has a lastName and firstName
How do I go about doing this?
You should be able to safely use NSDictionary's -valueForKeyPath: to retrieve each value from an item dict:
NSArray *names = [itemDict valueForKeyPath:#"volumeInfo.authors"];
NSString *title = [itemDict valueForKeyPath:#"volumeInfo.title"];
...

For loop not changing variables

First post here, so just wanted to say hi. Im a starting iOs developer, just for fun though.
Ive been breaking my head over the following code:
for (int n = 0; n <= iterations; n = n + 1) {
int interval = [[object valueForKey:#"interval"] integerValue];
NSTimeInterval singeltonTimestamp = interval * n;
NSLog(#"%d",(int)singeltonTimestamp);
[skeleton removeObjectForKey:#"date"];
[skeleton setObject:[[object objectForKey:#"start"] dateByAddingTimeInterval:singeltonTimestamp] forKey:#"date"];
[yuups addObject:skeleton];
NSLog(#"adding skeleton");
}
I have an object called skeleton and I am trying to add 4 of them (iterations = 3) with the date increasing with a certain interval. The singeltonTimestamp changes correctly (reading the NSLog output) but the date's for the skeletons are all the same, they dont increase.
"Object" contains a start date and an interval, I set some stuff (like the title) for the skeleton beforehand.
See this output
014-04-12 14:32:38.676 yuup[8397:60b] (
{
date = "2014-04-15 18:02:00 +0000";
title = test;
},
{
date = "2014-04-15 18:02:00 +0000";
title = test;
},
{
date = "2014-04-15 18:02:00 +0000";
title = test;
},
{
date = "2014-04-15 18:02:00 +0000";
title = test;
}
)
Help or tips are much appriciated. Thanks in advance
Try this
skeleton = [NSMutableDictionary dictionary];
[skeleton setObject:[[object objectForKey:#"start"] dateByAddingTimeInterval:singeltonTimestamp] forKey:#"date"];
[yuups addObject:skeleton];
You are adding same object again and again.. You have to make new instance before adding to the NSMutableArray

Reading in .CSV individual values

I have a .CSV File below that is already put into a nice format rather than a solid list of values.
How would i be able to read individual values from this list … for example 'Time of 5 & 6" and return the number?
I know how would retrieve this from a normal .csv file that is listed, however not from one that has a weird layout like this one. Any ideas?
Thank
If the column titles (such as "Time 4" and "Time of 5 & 6") are consistent, you could separate each line and then by commas, look for the index of the column title, and then grab the same column in the next line.
I haven't tested this, but I think it should work. Assuming your file is read in as a string:
NSArray *componentsByLine = [myFile componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
int firstIndex = 0;
int secondIndex = 0;
BOOL found = NO;
for(firstIndex = 0; firstIndex < componentsByLine.count; firstIndex++)
{
NSArray *componentsByComma = [[componentsByLine objectAtIndex:firstIndex] componentsSeparatedByString:#","];
for(secondIndex = 0; secondIndex < componentsByComma.count; secondIndex++)
{
if([[componentsByComma objectAtIndex:secondIndex] isEqualToString:#"Time of 5 & 6"])
{
found = YES;
break;
}
}
if(found)
break;
}
float requestedTime = [[[[componentsByLine objectAtIndex:firstIndex+1] componentsSeparatedByString:#","] objectAtIndex:secondIndex] floatValue];

sorting a JSON return into UITableView Sections and Rows

I'm trying to sort a JSON return into multiple sections according to each day. Here is the JSON return,
sales = (
{
"dis_dollars" = 0;
"dis_percent" = 0;
id = 111;
saleDay = 5;
saleMonth = 1;
saleTime = "20:02:39";
saleYear = 2014;
"total_price" = 25;
},
{
"dis_dollars" = 0;
"dis_percent" = 0;
id = 103;
saleDay = 2;
saleMonth = 1;
saleTime = "19:13:41";
saleYear = 2014;
"total_price" = 79;
},
{
"dis_dollars" = "0.55";
"dis_percent" = "0.10000000149012";
id = 101;
saleDay = 2;
saleMonth = 1;
saleTime = "10:41:11";
saleYear = 2014;
"total_price" = 22;
},
{
"dis_dollars" = 0;
"dis_percent" = 0;
id = 108;
saleDay = 1;
saleMonth = 1;
saleTime = "11:00:00";
saleYear = 2014;
"total_price" = 66;
}
);
}
I can get the number of sections if I do it this way
//...Connect to php script and get return json object
int saleDay = 0;
//Loop through json return
for (int i = 0;i < [sales count]; i++) {
NSDictionary* dict = [sales objectAtIndex:i];
Sale *eachSale =[[Sale alloc] initWithSaleId:[dict valueForKey:#"id"]
saleDay:[dict valueForKey:#"saleDay"]
saleMonth:[dict valueForKey:#"saleMonth"]
saleYear:[dict valueForKey:#"saleYear"]
saleTime:[dict valueForKey:#"saleTime"]
saleTotal:[dict valueForKey:#"total_price"]
saleDisDollars:[dict valueForKey:#"dis_dollars"]
saleDisPercent:[dict valueForKey:#"dis_percent"]];
NSLog(#"sale Day %#",eachSale.saleDay);
[_salesList addObject:eachSale];
int eachSaleDay = [eachSale.saleDay intValue];
// if the next day is different from the one before it, add a new section.
if (saleDay != eachSaleDay) {
_saleDaysCount += 1;
NSLog(#"eachSaleDay %i" ,eachSaleDay);
NSLog(#"salesDayCount %i" ,_saleDaysCount);
}
saleDay = eachSaleDay;
}
This will give me the correct number of sections, but how do I group the objects according to the day to find out the number of rows for each section, and what objects should go in each row?
I think I need to use NSSort Descriptors but I'm not sure where I would implement it and how to access the individual day arrays.
Any suggestions?
Thanks
I would simply add an additional field of type NSNumber with the complete date for each Sale while you are looping through your results.
eachSale.saleDateIdentifier = #(eachSale.saleYear.intValue * 10000 +
eachSale.saleMonth.intValue * 100 +
eachSale.saleDay.intValue);
Now it is easy to sort and count:
[_salesList sortUsingDescriptors:
#[[NSSortDescriptor sortDescriptorWithKey:#"saleDateIdentifier" ascending:NO]]];
NSArray *allDates = [_salesList valueForKeyPath:#"saleDateIdentifier"];
NSSet *uniqueDates = [NSSet setWithArray:allDates];
NSArray *sortedUniqueDates = [uniqueDates sortedArrayUsingDescriptors:
#[[NSSortDescriptor sortDescriptorWithKey:#"saleDateIdentifier" ascending:NO]]];
Your number of sections is sortedUniqueDates.count. For each section you could use the saleDateIdentifier to format the date string in titleForRowAtIndexPath.
BTW, maybe you do not want to use valueForKey in your init method for eachSale. Maybe you actually mean objectForKey. Better even, you should type the properties of the Sale class and use NSNumber and NSString as appropriate.

Resources