I have a Core Data model defined with two attributes
(Double) latitude
(Double) longitude
Now, I would like to fetched these objects and sort them depending on how far they are compared to the user's current location. I already know how to get the current location, but what I still can't figure out is how to sort the results depending on two attributes.
I've searched for something similar but I'm still a bit confused.
That'd be great if someone could point me to the right direction.
Thanks
Sorting with a comparator block is quite easy
NSArray *positions = //all fetched positions
CLLocation *currentLocation = // You said that you know how to get this.
positions = [positions sortedArrayUsingComparator: ^(id a, id b) {
CLLocation *locationA = [CLLocation initWithLatitude:a.latitude longitude:a.longitude];
CLLocation *locationB = [CLLocation initWithLatitude:b.latitude longitude:b.longitude];
CLLocationDistance dist_a= [locationA distanceFromLocation: currentLocation];
CLLocationDistance dist_b= [locationB distanceFromLocation: currentLocation];
if ( dist_a < dist_b ) {
return (NSComparisonResult)NSOrderedAscending;
} else if ( dist_a > dist_b) {
return (NSComparisonResult)NSOrderedDescending;
} else {
return (NSComparisonResult)NSOrderedSame;
}
}
As I just learned from lnafziger, you should add that useful hack/workaround¹, he is showing, to this.
¹choose form this words the one, that has the most positive connotation for you
You probably want to convert you long/lat pairs into a geographical distance between points and then sort on that single attribute.
Here's an article on some conversion methods, depending on what approximations you want to accept: http://en.wikipedia.org/wiki/Geographical_distance
Well, you can't.
Not just by sorting lat/long by itself anyway. :)
You will need to have a property that contains the distance from your current location. You can do this by adding a transient property which is calculated as needed or creating another array with the distances (probably easier).
To calculate your distance from your current location, use this method:
CLLocation *currentLocation = // You said that you know how to get this.
CLLocation *storedLocation = [CLLocation initWithLatitude:object.latitude
longitude:object.longitude];
/*
* Calculate distance in meters
* Note that there is a bug in distanceFromLocation and it gives different
* values depending on whether you are going TO or FROM a location.
* The correct distance is the average of the two:
*/
CLLocationDistance *distance1 = [currentLocation distanceFromLocation:storedLocation];
CLLocationDistance *distance2 = [storedLocation distanceFromLocation:currentLocation];
CLLocationDistance *distance = distance1 / 2 + distance2 / 2;
Related
Here is my Objective-C implementation of a disjoint set.
- Positive number point to parent.
- Negative number indicate root & children count. (So they each start disjointed at -1.)
- The index acts as the data I am grouping.
Seems to work ok... just had a couple questions.
find: How can I compress the path? Because I am not doing it recursively, do I have to store the path and loop it again to set after find root?
join: I am basing join on children count instead of depth!? I guess that is not right. Do I need to do something special during join if depths equal?
Thanks.
DisjointSet.h
#interface DisjointSet : NSObject
{
NSMutableArray *_array;
}
- (id)initWithSize:(NSInteger)size;
- (NSInteger)find:(NSInteger)item;
- (void)join:(NSInteger)root1 root2:(NSInteger)root2;
#end
DisjointSet.m
#import "DisjointSet.h"
#implementation DisjointSet
- (id)initWithSize:(NSInteger)size
{
self = [super init];
if (self)
{
_array = [NSMutableArray arrayWithCapacity:size];
for (NSInteger i = 0; i < size; i++)
{
[_array addObject:[NSNumber numberWithInteger:-1]];
}
}
return self;
}
- (NSInteger)find:(NSInteger)item
{
while ([[_array objectAtIndex:item] integerValue] >= 0)
{
item = [[_array objectAtIndex:item] integerValue];
}
return item;
}
- (void)join:(NSInteger)root1 root2:(NSInteger)root2
{
if (root1 == root2) return;
NSInteger data1 = [[_array objectAtIndex:root1] integerValue];
NSInteger data2 = [[_array objectAtIndex:root2] integerValue];
if (data2 < data1)
{
[_array setObject:[NSNumber numberWithInteger:data2 + data1] atIndexedSubscript:root2];
[_array setObject:[NSNumber numberWithInteger:root2] atIndexedSubscript:root1];
}
else
{
[_array setObject:[NSNumber numberWithInteger:data1 + data2] atIndexedSubscript:root1];
[_array setObject:[NSNumber numberWithInteger:root1] atIndexedSubscript:root2];
}
}
#end
For the find operation, there is no need to store the path (separately from your _array) or to use recursion. Either of those approaches requires O(P) storage (P = path length). Instead, you can just traverse the path twice. The first time, you find the root. The second time, you set all of the children to point to the root. This takes O(P) time and O(1) storage.
- (NSInteger)findItem:(NSInteger)item {
NSInteger root;
NSNumber *rootObject = nil;
for (NSInteger i = item; !rootObject; ) {
NSInteger parent = [_array[i] integerValue];
if (parent < 0) {
root = i;
rootObject = #(i);
}
i = parent;
}
for (NSInteger i = item; i != root; ) {
NSInteger parent = [_array[i] integerValue];
_array[i] = rootObject;
i = parent;
}
return root;
}
For the merge operation, you want to store each root's rank (which is an upper bound on its depth), not each root's descendant count. Storing each root's rank allows you to merge the shorter tree into the taller tree, which guarantees O(log N) time for find operations. The rank only increases when the trees to be merged have equal rank.
- (void)joinItem:(NSInteger)a item:(NSInteger)b {
NSInteger aRank = -[_array[a] integerValue];
NSInteger bRank = -[_array[b] integerValue];
if (aRank < bRank) {
NSInteger t = a;
a = b;
b = t;
} else if (aRank == bRank) {
_array[a] = #(-aRank - 1);
}
_array[b] = #(a);
}
You definitely should implement path compression using recursion. I would not even think about trying to do it non-recursively.
Implementing the disjoin-set datastructure should be very easy, and can be done in few lines. Its very, very easy to translate it from the pseudocode to any programming language. You can find the pseudocode on Wikipedia. (Unfortunately, I can't read Objective-C, so I cannot really judge wether your code is correct or not).
Yes. To implement highest ancestor compression without recursion you need to maintain your own list. Make one pass up the chain to get pointers to the sets that need their parent pointers changed and also to learn the root. Then make a second pass to update the necessary parent pointers.
The recursive method is doing the same thing. The first pass is the "winding up" of the recursion, which stores the sets needing parent pointer updates on the program stack. The second pass is in reverse as the recursion unwinds.
I differ with those who say the recursive method is always best. In a reasonable number systems (especially embedded ones), the program stack is of limited size. There are cases where many unions are performed in a row before a find. In such cases, the parent chain can be O(n) in size for n elements. Here collapsing by recursion can blow out the stack. Since you are working in Objective C, this may be iOS. I do not know the default stack size there, but if you use recursion it's worth looking at. It might be smaller than you think. This article implies 512K for secondary threads and 1Mb for the main thread.
Iterative, constant space alternative
Actually the main reason I'm writing is to point out that you still get O(log^* n) for n ammortized operations -- just a shade less efficient than collapsing, and still effectively O(1) -- if you only do factor-of-two compression: in the find operation, change parent pointers so that they point to the grandparents instead instead of the root. This can be done with iteration in constant storage. This lecture at Princeton talks about this algorithm and implements it in a loop with 5 lines of C. See slide 29.
I already have my brain broken with ai for tic-tac-toe type board game.
Problem is slow ai performance on high levels (even low levels has not so quick).
AI uses recursive method to find best move from number of available moves.
Here is some code:
#impelementation AIClass
- (NSMutableArray *)findLegalMoves
{
// Here is code that finds available legal moves
// Loop over board array
}
- (float)scoreOpponentsTurn:(float)min max:(float)max depth:(int)depth
{
moveType t; // moveType is struct defined in .h file
// typedef struct { int x, y; } moveType
NSMutableArray *moves = [self findLegalMoves];
for ( NSValue *val in moves ) {
[val getValue:&it]
float score = [self scoreMove:it min:min max:max depth:depth];
if ( score > min ) {
min = score;
}
if ( score > max ) {
min = 1000000000;
}
}
return min;
}
- (float)scoreMove:(moveType)m min:(float)min max:(float)max depth:(int)depth
{
NSMutableArray *changes = [[NSMutableArray alloc] init];
NSMutableArray *undo = [[NSMutableArray alloc] init];
float score;
[self.board evaluateChangesOnCol:m.x Row:m.y];
if ( [self.board checkForWin:&changes undo:&undo] ) {
score = 1000000000 + [self calcH]; //calcH - evals heuristic like sum of params
} else if ( depth > 0 ) {
score = - [self scoreOpponentsTurn:-1000000000 max:-min depth:depth - 1];
} else {
score = [self calcH];
}
[self.board applyChanges:undo];
}
- (moveType)findBestMove
{
NSMutableArray *legalMoves = [self findLegalMoves];
NSMutableArray *bestMoves = [[NSMutableArray alloc] init];
int min = -1000000000;
int max = 1000000000;
moveType move;
for ( NSValue *moveIt in legalMoves ) {
[moveIt getValue:&move];
float score = [self scoreMove:move min:min max:max depth:depth];
// Here i have some conditions to decide current move is best or not
}
// and pick random move from best moves and assign it to move variable
return move;
}
#end
And if number of legal moves like 3 and more (over recursive search it grows) this algorithm
works very slow.
It's my first objective-c experience.
Here is my guesses about how to improve performance:
Remove recursion (but I don't see another solution)
Use multithreading (how?)
May be use some ai library?
Sorry for my english.
Throwing away recursion in an algorithm that is a natural fit for recursion is not a good idea. Rather, you need to memoize your recursive solution. This common trick speeds up recursive solutions with common subproblems by orders of magnitude.
Consider these two sequences of moves:
x:(1,1) o:(2,1) x:(1,0) o:(2,0)
and
x:(1,0) o:(2,0) x:(1,1) o:(2,1)
The sequences are different, but they arrive at the same final state:
| | x | o
------------
| | x | o
Here is the root cause of the slowness: when your program arrives at a repeated state for the second time, it evaluates the position exactly as if it's the first time that it has seen it. This is wasteful: identical positions with three-move look-aheads will be evaluated four times; with four-move look-aheads, they would be evaluated eight times, and so on. This causes slowness proportional to 2^N, where N is the depth of your look-ahead.
Fixing this requires an addition of a lookup table. Given a state of the game, this table would give you the score for you or for the opponent, if such score has been calculated before. Your recursive functions would build a position key, and try a lookup in the score table. If the answer is there, it would be returned immediately. Otherwise, your function would construct the answer, and store it at the position key. Next time the same position occurs through a different series of moves, the answer would be reused.
You might want to try Alpha-beta pruning. It's possible that your game has as high branching factor, in which case you will want to avoid searching areas that won't affect the outcome.
You can also limit your search to a certain depth. Pick a depth that retrieves competent moves, but doesn't take too long.
On my tableview, prior to populating it after a search, I would like to add a minimum distance and a maximum distance of the current search in text fields at the top of the tableview. I can't seem to locate a method to do determine these parameters and my searches will vary from 2 to 50 results. I don't want to do it the hackcish way of just comparing the distance to each item from the current location in a loop. Can anyone point me to a clean method for determining min/max of an element in a mutable array?
If you need some value from every element in an array, then you're going to have to iterate over the array somehow. There's nothing wrong with a loop. Still, there are other ways than explicit loops to go through an array. Perhaps -[NSArray enumerateObjectsUsingBlock:] will make you happy:
__block CGFloat minDistance = INF;
__block CGFloat maxDistance = -INF;
[locationsArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
CGFloat dist = // calculate distance from obj to current location
if( dist < minDistance ){
minDistance = dist;
}
if( dist > maxDistance ){
maxDistance = dist;
}
}];
Other options for enumerating arrays can be found in the Collections Programming Topics document, under Enumeration.
You should also have a look at the Key-Value Collection Operators: [locationsArray valueForKey:#"#max.distance"] will pull out the maximum distance held by any of the members of the array. This may seem like exactly what you're looking for, but there's two things to be aware of. First, the objects have to already have that distance property -- you can't do any calculation as part of this procedure. Second, the property has to be an object (in this case, probably an NSNumber) not a primitive like CGFloat, because valueForKey: is going to send compare: to the result of each property access.
I have a set of dictionaries in an array. I display this data in a tableview. In the tableview i calculate the distance to each object and display that in the cell.
The data needs to be able to sort based on ascending distance, obviously per userlocation What's the best way to approach this? I thought of picking apart all of the dictionaries and inserting the distance and then letting loose the NSSortDescriptor, problem is, i'm way too lazy for that.
Right now im just looping through all of the data with the indexPath.row and displaying it.
You can easily sort with a the block based comparator api.
NSArray *rawData = [NSArray arrayWithContentsOfFile:pathDoc];
rawData = [rawData sortedArrayUsingComparator: ^(id a, id b) {
CLLocationDistance dist_a= [[a objectsForKey:#"coordinate"] distanceFromLocation: userPosition];
CLLocationDistance dist_b= [[b objectsForKey:#"coordinate"] distanceFromLocation: userPosition];
if ( dist_a < dist_b ) {
return NSOrderedAscending;
} else if ( dist_a > dist_b) {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}];
You should easy find an implementation for calculate_distance(user_position, a); with google.
a big noob needs help understanding things.
I have three UIViews stored inside a NSMutableArray
lanes = [[NSMutableArray arrayWithCapacity:3] retain];
- (void)registerLane:(Lane*)lane {
NSLog (#"registering lane:%i",lane);
[lanes addObject:lane];
}
in the NSLog I see: registering lane:89183264
The value displayed in the NSLog (89183264) is what I am after.
I'd like to be able to save that number in a variable to be able to reuse it elsewhere in the code.
The closest I could come up with was this:
NSString *lane0 = [lanes objectAtIndex:0];
NSString *description0 = [lane0 description];
NSLog (#"description0:%#",description0);
The problem is that description0 gets the whole UIView object, not just the single number (dec 89183264 is hex 0x550d420)
description0's content:
description0:<Lane: 0x550d420; frame = (127 0; 66 460); alpha = 0.5; opaque = NO; autoresize = RM+BM; tag = 2; layer = <CALayer: 0x550d350>>
what I don't get is why I get the correct decimal value with with NSLog so easily, but seem to be unable to get it out of the NSMutableArray any other way. I am sure I am missing some "basic knowledge" here, and I would appreciate if someone could take the time and explain what's going on here so I can finally move on. it's been a long day studying.
why can't I save the 89183264 number easily with something like:
NSInteger * mylane = lane.id;
or
NSInteger * mylane = lane;
thank you all
I'm really confused as to why you want to save the memory location of the view? Because that's what your '89183264' number is. It's the location of the pointer. When you are calling:
NSLog (#"registering lane:%i",lane);
...do you get what's actually being printed out there? What the number that's being printed means?
It seems like a really bad idea, especially when if you're subclassing UIView you've already got a lovely .tag property which you can assign an int of your choosing.
You're making life infinitely more complex than it needs to be. Just use a pointer. Say I have an array containing lots of UIViews:
UIView *viewToCompare = [myArray objectAtIndex:3];
for (id object in myArray) {
if (object == viewToCompare) {
NSLog(#"Found it!");
}
}
That does what you're trying to do - it compares two pointers - and doesn't need any faffing around with ints, etc.