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.
Related
I'm declaring a variable just to limit the number of results filtering a NSDictionary. Is there any other way to do this avoiding the extra variable?
My code:
//Pick one part from each item
__block int partsCounter = 0;
NSSet *itemsParts = [self.deckDictionary keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) {
//filter with itemRef value
CollectiblePart* part = (CollectiblePart*)obj;
if([candidatesSet containsObject:[NSNumber numberWithInt: part.itemRef]]){
if(partsCounter < quantity)
{
partsCounter++;
return YES;
}else{
//stop the filtering
return (*stop = NO);
}
}else{
return NO;
}
}];
No, that's the best way to do it.
While the method allows the block to be exited mid way through, it has no idea why it would have to do that, and as such doesn't accommodate any aids in doing so.
In your semantics, you need to keep a tally to keep track if something exceeds a particular threshold. Having a variable to do that makes sense.
I want to sort a NSMutableArray which has NSArrays with respect to the value at the index 1 of the NSArray. I'll try to draw a picture of arrays.
NSMutableArray *ultimateHighscoreArray = {
( (NSString) userName, (double) score, (int) numOfCorrectAnswers ) ,
( John , 4.5 , 3 ) ,
( Terry , 7.5 , 1) ,
... }
The first array within the NSMutableArray is an example which shows how examples are located. Second and third are how the values actually are. So, what I want is to sort these arrays having the array containing higher value at first index to go higher up in the ranking. For this example the array that has 7.5 which is Terry Array should go before the one that has 4.5 . I want the results to be held in a NSMutableArray in decreasing order. Thank you.
This should do it:
[ultimateHighscoreArray sortUsingComparator:^(id obj1, id obj2) {
NSNumber *score1 = [obj1 objectAtIndex:1];
NSNumber *score2 = [obj2 objectAtIndex:2];
// Reverse the comparison here (compare score2 to score1)
// in order to get a descending order
return [score2 compare:score1];
}];
A general advice: your data structure would be clearer if it were an array of NSDictionary instances or even an array of custom objects (e.g., your custom Score class). In those cases, you could also use NSSortDescriptor to sort the array, which would result in cleaner, easier-to-read code.
The sortUsingComparator: method allows you to sort an array using a block, e.g.:
[ultimateHighscoreArray sortUsingComparator:^(id obj1, id obj2) {
return [[obj1 objectAtIndex:1] compare:[obj2 objectAtIndex:1]];
}];
For clarity, it would probably be better to use an array of dictionaries (or instances of a custom class) for this data structure.
You can write a custom comparator like this :)
[ultimateHighscoreArray sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSArray *arrayA = (NSArray *)obj1;
NSArray *arrayB = (NSArray *)obj2;
double scoreA = [arrayA objectAtIndex:1];
double scoreB = [arrayB objectAtIndex:1];
if (scoreA > scoreB) {
return NSOrderedDescending;
} else if (scoreA < scoreB) {
return NSOrderedAscending;
} else {
return NSOrderedSame;
}
}];
I have a Car class. It's got a property called enginePower. On the other hand I have an NSArray that contains more than 50 car objects. How would I select the car with the highest enginePower which at the same time is less than the given value. To be more clear:
BMW X5-345 hp
Audi A3-200 hp
BMW 525i -225 hp
VW Passat CC-175 hp
.....
Now, from this array of cars when I ask for the car with the highest enginePower which is less than 320 it should give me BMW 525i. Is it possible to achieve. I mean is there a nice and easy way or does it need lots of lines of code?
The answer provided by #Jasarien would work just fine, but if you want to avoid writing the code to loop through you might try something like:
- (Car *)getHighestPowerFromCars:(NSArray *)carArray atLeast:(NSNumber *)minPower {
NSArray *descriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"enginePower" ascending:NO]];
NSArray *sortedArray = [carArray sortedArrayUsingDescriptors:descriptors];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"enginePower >= %#", minPower];
NSArray *filteredArray = [sortedArray filteredArrayUsingPredicate:predicate];
return [filteredArray objectAtIndex:0];
}
Sort the array using the engine power property, then loop through the array until you find an enginePower value that is greater than the one specified. Then take the value of the object in currentArrayIndex - 1.
You can do this by using -compareUsingSelector: on an NSMutableArray or -sortedArrayUsingSelector: on an NSArray (which will return a new, sorted, autoreleased array).
You can create a method on your Car class named something like -compareUsingEnginePower: which will take another Car object as the parameter.
Then you can compare the two enginePower properties and return one of NSOrderedSame, NSOrderedAscending or NSOrderedDescending.
Straightforward iteration through the array, looking only at cars below the power limit, and picking the one with the highest power:
— (Car *)getHighestPowerFromCars:(NSArray *)carArray lessThan:(NSNumber *)maxPower
{
NSNumber* highest = nil;
Car* highestCar = nil;
for (Car* car in carArray)
{
NSNumber* power = car.enginePower;
if ([power compare:maxPower] == NSOrderedAscending])
{
if (highest == nil || [power compare:highest] == NSOrderedDescending])
{
highest = power;
highestCar = car;
}
}
}
return highestCar;
}
But there isn't any reason really why enginePower should be an NSNumber and not for example a double. Assuming that the power is never negative:
— (Car *)getHighestPowerFromCars:(NSArray *)carArray lessThan:(double)maxPower
{
double highestPower = -1.0;
Car* highestCar = nil;
for (Car* car in carArray)
{
double power = car.enginePower;
if (power < maxPower && power > highestPower))
{
highestPower = power;
highestCar = car;
}
}
return highestCar;
}
But then sorting and predicates are soooo fast...
People I'd like to see if an element at index[i] is not present in a different (or current ) array.
So for instance if my array looked somewhat like this
[wer, wer4 , wer5 , werp , klo ...
Then I would like to see if aExerciseRef.IDE ( which is "sdf" for instance ) does or does not exist at index[i].
I assume I'd have to use some sort of iterator ..
for( int i = 0; i < 20; i++ )
{
if([instruct objectAtIndex:index2 + i] != [instruct containsObject:aExerciseRef.IDE] )
NSLog(#"object doesn't exist at this index %i, i );
else
NSLog(#"well does exist")
}
I know this doesn't work , it's just to elaborate what I'd like to achieve.
edit:
I'm going to try to elaborate it a little more and be more specific.
1) First of all aExerciseRef.IDE changes everytime it get's called so one time it is "ret" another time it's "werd".
2) Imagine an array being filled with aExerciseRef.IDE's then I would like to compare if the elements in this array exist in the instruct array.
So I would like to see if the element at let's say position 2 (wtrk)
[wer, wtrk, wer , sla ...
exists in the array which was being filled with the aExerciseRef.IDE's.
I hope I've been more clear this time.
Sir Lord Mighty is partially correct. Yes, your comparison is wrong. No, his solution won't work.
Here's one that will:
if (index < [anArray count] && [[anArray objectAtIndex:index] isEqual:anObject]) {
NSLog(#"Got it!");
} else {
NSLog(#"Don't have it.");
}
Alternatively, you can use the containsObject: method to achieve the same thing:
if ([anArray containsObject:aExerciseRef.IDE]) {
NSLog(#"Got it!");
} else {
NSLog(#"Don't have it.");
}
The second option will not give you the index of the object, but that is easily rectified using:
NSInteger index = NSNotFound;
if ([anArray containsObject:aExerciseRef.IDE]) {
index = [anArray indexOfObject:aExerciseRef.IDE];
...
}
Your example makes no sense at all, and does nothing to clarify the question. You are doing a comparison between an expression with type (id)
[instruct objectAtIndex:index2 + i]
and one with type BOOL
[instruct containsObject:aExerciseRef.IDE]
And if the object you are looking for is at index x in an array, then it goes without saying that containsObject on the array will return YES for that object.
If what you want to accomplish is simply what you state in the title, then it's as easy as:
if ([[anArray objectAtIndex:index] == anObject])
NSLog (#"Got it!");
else
NSLog (#"Don't have it.");
I'm working on a roguelike using Objective-C/Cocoa to learn more. I've gotten most of the basic functionality out of the way, but I still have one problem I've been trying to figure out.
Here's a breakdown of the process:
First, the map is loaded:
NSString* mapPath = [[NSBundle mainBundle] pathForResource:mapFileName ofType:mapFileType];
NSURL* mapURL = [NSURL fileURLWithPath: mapPath];
currentMap_ = [[Map alloc] initWithContentsOfURL: mapURL];
worldArray = [[NSMutableArray alloc] init];
itemArray = [[NSMutableArray alloc] init];
[self populateMap];
return;
Then, in the populateMap function, it goes through each cell of the loaded map, using NSPoints and a loop, and creates objects based on the data from the map in WorldArray. For items, normal floor is put in where the item is, and an item is then made in itemArray. Both arrays are 30x30, as determined by the height of the map.
Here is the populateMap code:
- (void)populateMap
{
NSPoint location;
for ( location.y = 0; location.y < [currentMap_ height]; location.y++ )
{
for ( location.x = 0; location.x < [currentMap_ width]; location.x++ )
{
char mapData = [currentMap_ dataAtLocation: location];
for ( GameObject *thisObject in worldDictionary )
{
//NSLog(#"char: <%c>", [thisObject single]);
if ( mapData == [thisObject single])
{
NSString* world = [thisObject className];
//NSLog(#"(%#) object created",thisObject);
[self spawnObject:world atLocation:location];
}
}
for ( Item *thisObject in itemDictionary )
{
//NSLog(#"char: <%c>", [thisObject single]);
if ( mapData == [thisObject single] )
{
NSString* item = [thisObject className];
NSString* floor = [NormalFloor className];
//NSLog(#"(%#) object created",thisObject);
[self spawnItem:item atLocation:location];
[self spawnObject:floor atLocation:location];
}
}
if ( mapData == '1'
&& [player_ stepsTaken] <= 0)
{
//NSLog(#"player spawned at (%f, %f)",location.x,location.y);
player_ = [[Player alloc] initAtLocation: location];
}
if ( mapData == '1' )
{
//NSLog(#"floor created at (%f, %f)",location.x,location.y);
[worldArray addObject:[[NormalFloor alloc] initAtLocation: location]];
}
}
}
[self setNeedsDisplay:YES];
}
This is what is called when things are spawned:
- (void)spawnObject: (NSString*) object atLocation: (NSPoint) location
{
//NSLog(#"(%#) object created",thisObject);
[worldArray addObject:[[NSClassFromString(object) alloc] initAtLocation: location]];
}
- (void)spawnItem: (NSString*) item atLocation: (NSPoint) location
{
//NSLog(#"(%#) object created",thisObject);
[itemArray addObject:[[NSClassFromString(item) alloc] initAtLocation: location]];
}
worldArray and itemArray are what the game works on from that moment onwards, including the drawing. The player is inside of worldArray as well. I'm considering splitting the player into another array of characterArray, to make it easier when I add things like monsters in the not so distant future.
Now, when I load a new level, I had first considered methods like saving them to data and loading them later, or some sort of savestate function. Then I came to the realization that I would need to be able to get to everything at the same time, because things can still happen outside of the player's current scope, including being chased by monsters for multiple floors, and random teleports. So basically, I need to figure out a good way to store worldArray and itemArray in a way that I will be able to have levels of them, starting from 0 and going onward. I do need a savestate function, but there's no point touching that until I have this done, as you shouldn't actually be allowed to save your game in roguelikes.
So to reiterate, I need to have one set of these arrays per level, and I need to store them in a way that is easy for me to use. A system of numbers going from 0-upward are fine, but if I could use something more descriptive like a map name, that would be much better in the long run.
I've figured out my problem, I'm using an NSMutableDictionary for each and storing them with the keys that correspond to each level. Works like a charm. Bigger problems elsewhere now.
I figured it out, I'm using NSMutableDictionaries, one for each array (objects, items, eventually characters). They're stored using the name of the level. Works like a charm.