Compare two hour strings Objective C - ios

I have an string with an hour in it, for example "15:15", and an array of other hours in strings ex: #["15:00","16:00","17:00"] I should compare the single string with the array ones in order to get the ETA in a bus station, I tried this code but it keeps iterating and gives me the last greater value in the array, not the first greater value as I need.
int i = 0;
horaArribada = [[[objects objectAtIndex:0]objectForKey:#"Horaris"]objectAtIndex:i];
while ([hora compare:horaArribada]) {
i++;
if (i >= [[[objects objectAtIndex:0]objectForKey:#"Horaris"]count]) {
break;
}else{
horaArribada = [[[objects objectAtIndex:0]objectForKey:#"Horaris"]objectAtIndex:i];
}
}
self.tfHoraArribada.text = horaArribada;
}
}
Where objects is a query from Parse and hora the single string with an hour in it.

You appear to be doing a lot of extra work to iterate over your array. Instead, try a different format for your loop:
for (NSString *horaArribada in [[objects objectAtIndex:0] objectForKey:#"Horaris"]) {
if ([hora compare:horaArribada] == NSOrderedAscending) {
self.tfHoraArribada.text = horaArribada;
break;
}
}
This assumes that your Horaris array is already sorted such from smallest to largest. Also, the logic will not work for the midnight rollover, so you'll probably want to account for that.

Related

Timely accurate continuous data algorithm

I want to create an algorithm but not sure how to start.
This algorithm will actually be a method that accepts an array of N objects with some of the attributes, createdAt, value.
I will sort the array from older to new (createdAt) and then I have to find out how consistent the available data is, meaning, for every one hour do I have at least 5 records, and for every half an hour 2 records.
Example-testcode:
- (void) normalizeData:(NSArray*)records
{
// sort the records
NSArray* sortedRecords = [records sortWithCreatedAt];
// split all dates in the records, distinct them, and create a dictionary with a key for every date, for value create another dictionary with the hour as key and the records as the value.
NSArray* distinctDates = [sortedRecords valueForKeyPath:#"#distinctUnionOfObjects.createdAt"]; // should only consider month-day-year-hour
NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
for (NSDate* date in distinctDates)
{
NSString* stringDate = [date string];
NSArray* recordsForDate = [sortedRecords valueForKeyPath:[NSString stringWithFormat:#"[collect].{createdAt=%#}.self", stringDate]]; // let's say you got them with this line
[dictionary setObject:recordsForDate forKey:date];
}
for (NSDate* keyDate in dictionary)
{
NSArray* records = [dictionary objectForKey:keyDate];
Record* previousRecord = nil;
for (Records* record in records)
{
// I'll have to keep the previous record and compare the time difference with the new
NSInteger secondsAfterDate = 0;
if (previousRecord)
{
secondsAfterDate = [record.createdAt timeIntervalSinceDate:previousRecord.createdAt];
// add logic to create trend difference in a model that has for every hour of the records count, the records and suffice description
// logic if the records count and timespan is suffice.
}
previousRecord = record;
}
}
}
I would appreciate any contribution to the process in the method.
Also the ultimate goal is to create a return (invoke a block handler) for every result of the records that processed.
The logic should end with, 5 records at least per hour and a timespan between them under 15 minutes.
Take the total length of time of record collection (difference between createdAt of first record and createdAt of last record) and discretize it into bins. Place each object in the appropriate bin. Then used a sliding window with two window sizes (30 minutes and 60 minutes). As you walk along the array, continually evaluate whether the conditions you describe are met.
Note that for the above approach it's important to properly define the bin width as the resolution of your timestamping process. Since you don't indicate this in your post, feel free to comment if this is a problem.

Strange performance issue with nested (for-)loops

Using Instruments to look for bottlenecks in my code I stumbled upon some weird observation:
I am parsing two csv files; one contains about 3000 customers, the other about 8000 orders.
After that I'm iterating over the two arrays containing the customers and orders to detect relationships between each other. That way I not only find the corresponding orders for each customer but also determine their last orders; according to that date they are categorized.
At the beginning neither of the two arrays were sorted, so for every customer i went through ALL remaining orders, which took like 3-4 secs. Then I came up with the idea to sort both arrays using the customer ids. Now I know that the first orders of the orders-array correspond to the first customer. As soon I got a different customer id in my order, I know, that this has to be the next customer's order. so I remove the orders that I already processed and do the same for the next customer. I already have my next tweaking idea (just using the index of a block enumeration and keep track of that index. That way I don't have to remove any entries. Maybe I some more performance boost. But currently I have another issue, which I explain after the following code:
- (void) determineLastOrders {
for (Kunde * kunde in _kundenArray) {
[self determineLastOrder:kunde];
}
}
- (void) determineLastOrder: (Kunde*)kunde {
NSMutableArray *bestellungenToRemove = [[NSMutableArray alloc] init];
/* go through all (remaining) orders (after the loop the matching will be removed) and determine the next ones to remove */
for (Bestellung * bestellung in _bestellungenMutArr) {
if ([[bestellung bestKdNr] isEqualToString:kunde.kdnr]) {
if ( kunde.lastOrder == nil) {
kunde.lastOrder = _orangeDate; //"init"
}
else if ([kunde.lastOrder compare:[bestellung bestDatum]] == NSOrderedAscending) {
kunde.lastOrder = [bestellung bestDatum];
}
[bestellungenToRemove addObject:bestellung];
}
else {
//as all orders are ordered by the customer id we can abort iteration
//after we went past the current id
break;
}
}
// after the iteration we can safely remove the instances from the array
// this is quite efficient as due to the order of the orders we ALWAYS remove from
// the beginning of the array -> http://ridiculousfish.com/blog/posts/array.html
[_bestellungenMutArr removeObjectsInArray: bestellungenToRemove];
if ([kunde.lastOrder compare:_orangeDate] == NSOrderedDescending) {
[kunde setDotPath: #"green.png"];
}
else if (kunde.lastOrder == nil) {
[kunde setDotPath: #"red.png"];
}
else {
[kunde setDotPath: #"orange.png"];
}
}
I found out that the block of the 2 functions roughly takes about 400ms. My next thought was, that I might get some small performance gain, if I don't use 2 functions and thus save about 3000 function calls.
So I kicked out the 1st function and simply put my for loop around the contents of the 2nd function. That time it took roughly about 10 times longer?!? Why could that be?
Thanks
EDIT1:
The slower code version with nested loop:
- (void) determineLastOrders
{
NSMutableArray *bestellungenToRemove = [[NSMutableArray alloc] init];
for (Kunde * kunde in _kundenArray)
{
/* go through all (remaining) orders (after the loop the matching will be removed) and determine the next ones to remove */
for (Bestellung * bestellung in _bestellungenMutArr)
{
if ([[bestellung bestKdNr] isEqualToString:kunde.kdnr])
{
if ( kunde.lastOrder == nil)
{
kunde.lastOrder = _orangeDate; //"init"
}
else if ([kunde.lastOrder compare:[bestellung bestDatum]] == NSOrderedAscending)
{
kunde.lastOrder = [bestellung bestDatum];
}
//As this Bestellung already has had a date comparison (equal by kdnr)
//we won't need to visit it again by our next customer
[bestellungenToRemove addObject:bestellung];
}
else
{ //as all orders are ordered by the customer id we can abort iteration
//after we went past the current id
break;
}
}
//after the iteration we can safely remove the instances from the array
//this is quite efficient as due to the order of the orders we ALWAYS remove from
//the beginning of the array -> http://ridiculousfish.com/blog/posts/array.html
[_bestellungenMutArr removeObjectsInArray: bestellungenToRemove];
if ([kunde.lastOrder compare:_orangeDate] == NSOrderedDescending)
{
[kunde setDotPath: #"green.png"];
}
else if (kunde.lastOrder == nil)
{
[kunde setDotPath: #"red.png"];
}
else
{
[kunde setDotPath: #"orange.png"];
}
}
}
In the version with just a single function, you've left the initialization of the bestellungenToRemove mutable array outside the outer loop. This means you don't get a new one for each iteration of the outer loop, as you do in the two-function version.
Since that array gets larger each time through, the removeObjects: call takes longer and longer as that array grows.
So, move it back into the outer loop and you should have the same performance in both versions.

Objective-c: Most efficient way to get the shortest range from a collection (NSArray) with ranges

I have an NSArray that contains multiple objects which in itself have date ranges NSDate *start and NSDate *end.
What I want to do is to iterate through this array to find the shortest range (between Start and End), based on the current date. Something like this:
Date range Start 1 >----------< Date range End 1
Date range Start 2 >-< Date range End 2
|
Current date
In the example above I would like to get the object that contains Date range start 2 and Date range End 2.
Any ideas and suggestions on how to achieve this?
Update
With based on current date I mean that the current date should be somewhere inside the range. I don't want a range that has an end date that is before the current date, nor a range that has a start date that is in the future.
There are a couple options, depending on how in depth you want the results to be. The first (and easiest) way would be to sort the array by smallest date range:
array = array1 sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
double a = [obj1.endDate timeIntervalSinceDate:obj1.startDate];
double b = [obj2.endDate timeIntervalSinceDate:obj2.startDate];
if ( a < b ) {
return (NSComparisonResult)NSOrderedAscending;
} else if ( a > b ) {
return (NSComparisonResult)NSOrderedDescending;
} else {
return (NSComparisonResult)NSOrderedSame;
}
}
Then when you need to check for the shortest one containing today's date you can just start at the beginning of the array and check if the startdate is before now and the enddate is after now. The first object that matches that criteria is your smallest range around today.
NSDate *date = [NSDate date];
Object *foundObject;
for(Object *obj in array)
{
if([obj.startDate timeIntervalSinceDate:date] <= 0 && [obj.endDate timeIntervalSinceDate:date] >= 0)
{
foundObject = obj;
break;
}
}
If you want to go more in depth you can use a predicate to get a filtered array of all objects that surround today's date. then you can get the shortest range and every other range that includes the date you are looking for.
NSPredicate *pred = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
if([evaluatedObject.startDate timeIntervalSinceDate:date] <= 0 && [evaluatedObject.endDate timeIntervalSinceDate:date] >= 0)
{
return true;
}
return false;
}];
NSArray *array = [array1 filteredArrayUsingPredicate:pred];
I think, this should be a good start point, but I can't provide working code since there is no clear definition, so:
// Result with minimum range
// Assuming that DateRangeObject has start and end properties of NSDate
DateRangeObject *result = nil;
// Array containing DateRangeObject objects
NSArray *arr /* = TODO: provide the content for an array */;
if (arr.count) { /* only if the array contains something */
// Initial result
result = arr[0];
double minTS = DBL_MAX; // max double value, not zero ;) lol
for (DateRangeObject *dro in arr) {
// Get the timestamps for start and end;
double tss = [dro.start timeIntervalSince1970];
double tse = [dro.end timeIntervalSince1970];
// Difference between end and start (positive value)
double diff = tse - tsa;
if (minTS < diff) {
minTS = diff;
// Current minimum
result = dro;
}
}
}

Compare 2 Objects in Objective-C

In my application, I want to compare 2 core data instances of the entity "Workout". I want to check if the 2 objects have identical attribute values for all of their attributes. Essentially if the two objects are the same minus the relationship, whosWorkout. Is there any way to do this without manually checking every single attribute? I know I could do:
if(object1.intAttr == object2.intAttr){
NSLog(#"This attribute is the same");
}
else{
return;
}
repeat with different attributes...
Is there any core data method to make this a bit less tedious?
First I would create an isEqual method in the Workout subclass like this...
-(BOOL)isEqualToWorkout:(Workout*)otherWorkout
{
return [self.attribute1 isEqual:otherWorkout.attribute1]
&& [self.attribute2 isEqual:otherWorkout.attribute2]
&& [self.attribute3 isEqual:otherWorkout.attribute3]
&& [self.attribute4 isEqual:otherWorkout.attribute4]
...;
}
Then whenever you want to compare to Workout objects just use...
BOOL equal = [workout1 isEqualToWorkout:workout2];
You can iterate through the attributes by name.
for (NSString *attribute in object.entity.attributesByName) {
if ([[object valueForKey:attribute] intValue] !=
[[object2 valueForKey:attribute] intValue]) {
return NO;
}
}
return YES;
This assumes all integer attributes. You could do a switch statement to check for the class with the class method and deal with different data types as well.
If you need to compare whether one object represents a greater or lesser value than another object, you can’t use the standard C comparison operators > and <. Instead, the basic Foundation types, like NSNumber, NSString and NSDate, provide a compare: method:
if ([someDate compare:anotherDate] == NSOrderedAscending) {
// someDate is earlier than anotherDate
}
I ended up doing the following:
-(BOOL)areEqual:(Workout *)firstWorkout secondWorkout:(Workout *)secondWorkout{
NSArray *allAttributeKeys = [[[firstWorkout entity] attributesByName] allKeys];
if([[firstWorkout entity] isEqual:[secondWorkout entity]]
&& [[firstWorkout committedValuesForKeys:allAttributeKeys] isEqual:[secondWorkout committedValuesForKeys:allAttributeKeys]]) {
return YES;
}
else{
return NO;
}
}

IOS Objective C - Updating NSArray values from another NSArray

I have a NSArray with objects Called Houses, each object has 3 fields = id,address,price
I can set the value by using
[house setValue:#"£100k" forKey:#"price"];
However I have another NSArray called Movements, each object has 2 fields, id & price
so how do I update the 1st array with details from the 2nd array.. in english it I trying to do "Update house price with movement price where house id = movement id"
Thanks in advance
Sounds like you want a double loop:
for (House* house in houses)
for (Movement* movement in movements)
{
if (house.id == movement.id)
house.price = movement.price
}
If there will only be one such instance you may want to break early, you'll need an extra BOOL for this:
BOOL breaking = false;
for (House* house in houses)
{
for (Movement* movement in movements)
{
if (house.id == movement.id)
{
house.price = movement.price
breaking = true;
break;
}
}
if (breaking) break;
}
Edit: If you are doing this kind of thing frequently, you probably want to construct a dictionary keyed on the id field so you can look up an object quickly rather than by looping the whole array. NSDictionary is the class you want for this, also note that keys must be objects, so if your id field is an int you'll want to convert it to an NSNumber with [NSNumber numberWithInt:] before using it as a key.

Resources