Find longest path between root node and any child - ios

I have an array of elements, some of whom have children, who have children in turn and so on. I know the direct children of each element, and have a list of all descendents for each element.
-(NSMutableArray *)descendents:(Element *)e {
NSMutableArray * descendents = [NSMutableArray new];
for (NSString * uID in e.children){
[descendents addObject:uID];
Element * k = elements[uID][#"element"];
[descendents addObjectsFromArray:[self descendents:k]];
}
return descendents;
}
I can determine the root element by comparing the total number of descendents for each element. I can find the shortest route between the root and any given element given this:
-(int)find:(NSString *)uniqueID forElement:(Element *)e {
int distance = 0;
if ([e.children containsObject:uniqueID]){ //immediate child
distance ++; //increment distance
return distance; //return
} else if ([e.descendents containsObject:uniqueID]){ //grand child etc
distance ++;
for (NSString * uID in e.children){
Element * k = elements[uID][#"element"];
distance += [self find:uniqueID forElement:k];
return distance;
}
}
return 0;
}
What I want to do is find the longest distance between an element and the root. I'm thinking about going back up the tree from elements with zero children or adding an array of distances between elements in the mapping function. Struggling as to the cleanest approach - any ideas?
EDIT:
solution based on user3290797's answer below, tracking reference to max number of parents:
-(int)parentHeight:(NSString *)uID {
int maxHeight = 0;
Element * e = elements[uID][#"element"];
for (NSString * parentID in e.parents){
int height = [self parentHeight:parentID];
maxHeight = (height > maxHeight) ? height : maxHeight;
}
return maxHeight + 1;
}

The longest distance between an element and the root is called the height (or depth) of the tree.
One way to find it is to recursively traverse the tree and calculate the height of every node as the maximum of its children's heights plus one.
In pseudocode:
function height(node) {
maxChildHeight = 0
for(child in node.children) {
h = height(child)
if(h > maxChildHeight) {
maxChildHeight = h
}
}
return maxChildHeight + 1
}

If not a lot of nodes, calculate each distance and assign an ID for each , then check the longest of them , this is slow but works hahaha

Related

Objective C " * " syntax and usage

I am re-writing the particle filter library of iOS in Swift from Objective C which is available on Bitbucket and I have a question regarding a syntax of Objective C which I cannot understand.
The code goes as follows:
- (void)setRssi:(NSInteger)rssi {
_rssi = rssi;
// Ignore zeros in average, StdDev -- we clear the value before setting it to
// prevent old values from hanging around if there's no reading
if (rssi == 0) {
self.meters = 0;
return;
}
self.meters = [self metersFromRssi:rssi];
NSInteger* pidx = self.rssiBuffer;
*(pidx+self.bufferIndex++) = rssi;
if (self.bufferIndex >= RSSIBUFFERSIZE) {
self.bufferIndex %= RSSIBUFFERSIZE;
self.bufferFull = YES;
}
if (self.bufferFull) {
// Only calculate trailing mean and Std Dev when we have enough data
double accumulator = 0;
for (NSInteger i = 0; i < RSSIBUFFERSIZE; i++) {
accumulator += *(pidx+i);
}
self.meanRssi = accumulator / RSSIBUFFERSIZE;
self.meanMeters = [self metersFromRssi:self.meanRssi];
accumulator = 0;
for (NSInteger i = 0; i < RSSIBUFFERSIZE; i++) {
NSInteger difference = *(pidx+i) - self.meanRssi;
accumulator += difference*difference;
}
self.stdDeviationRssi = sqrt( accumulator / RSSIBUFFERSIZE);
self.meanMetersVariance = ABS(
[self metersFromRssi:self.meanRssi]
- [self metersFromRssi:self.meanRssi+self.stdDeviationRssi]
);
}
}
The class continues with more code and functions which are not important and what I do not understand are these two lines
NSInteger* pidx = self.rssiBuffer;
*(pidx+self.bufferIndex++) = rssi;
Variable pidx is initialized to the size of a buffer which was previously defined and then in the next line the size of that buffer and buffer plus one is equal to the RSSI variable which is passed as a parameter in the function.
I assume that * has something to do with reference but I just can't figure out the purpose of this line. Variable pidx is used only in this function for calculating trailing mean and standard deviation.
Let explain those code:
NSInteger* pidx = self.rssiBuffer; means that you are getting pointer of the first value of the buffer.
*(pidx+self.bufferIndex++) = rssi; means that you are setting the value of the buffer at index 0+self.bufferIndex to rssiand then increase bufferIndex by 1. Thanks to #Jakub Vano point it out.
In C++, it will look like that
int self.rssiBuffer[1000]; // I assume we have buffer like that
self.rssiBuffer[self.bufferIndex++] = rssi

Find nearest float in array

How would I get the nearest float in my array to a float of my choice? Here is my array:
[1.20, 1.50, 1.75, 1.95, 2.10]
For example, if my float was 1.60, I would like to produce the float 1.50.
Any ideas? Thanks in advance!
You can do it by sorting the array and finding the nearest one.
For this you can use sortDescriptors and then your algorithm will go.
Even you can loop through, by assuming first as the required value and store the minimum absolute (abs()) difference, if next difference is lesser than hold that value.
The working sample, however you need to handle other conditions like two similar values or your value is just between two value like 2 lies between 1 and 3.
NSArray *array = #[#1.20, #1.50, #1.75, #1.95, #2.10];
double my = 1.7;
NSNumber *nearest = array[0];
double diff = fabs(my - [array[0] doubleValue]);
for (NSNumber *num in array) {
double d = [num doubleValue];
if (diff > fabs(my - d) ) {
nearest = num;
diff = my - d;
}
}
NSLog(#"%#", nearest);

Finding the nearest, lower number in a sorted NSArray

I have a sorted array of times like so
[0.0, 1.2, 4.3, 5.9, 7.2, 8.0]
While an audio file plays, I want to be able to take the current time and find what the nearest, lower number is in the array.
My approach would be to traverse the array, possible in reverse order as it feels like it should be faster. Is there a better way?
The playback SHOULD be linear, but might be fast-forwarded/rewound, so I would like to come up with a solution that takes that into account, but I'm not really sure how else to approach the problem.
The method you are looking for is -[NSArray indexOfObject:inSortedRange:options:usingComparator:]. It performs a binary search. With the options:NSBinarySearchingInsertionIndex option, if the value isn't found exactly, it returns the index where the object would be inserted, which is the index of the least larger element, or the count of items in the array.
NSTimeInterval currentTime = ...;
NSUInteger index = [times indexOfObject:#(currentTime)
inSortedRange:NSMakeRange(0, times.count)
options:NSBinarySearchingInsertionIndex
usingComparator:^(id object0, id object1) {
NSTimeInterval time0 = [object0 doubleValue];
NSTimeInterval time1 = [object1 doubleValue];
if (time0 < time1) return NSOrderedAscending;
else if (time0 > time1) return NSOrderedDescending;
else return NSOrderedSame;
}];
// If currentTime was not found exactly, then index is the next larger element
// or array count..
if (index == times.count || [times[index] doubleValue] > currentTime) {
--index;
}
The fastest* way to find something in a sorted array is binary search: if there are n items, check the element at index n/2. If that element is greater than what you're looking for, check the element at index n/4; otherwise, if it's less than what you're looking for, check the element at index 3n/4. Continue subdividing in this fashion until you've found what you want, i.e. the position where the current time should be. Then you can pick the preceding element, as that's the closest element that's less than the current time.
However, once you've done that once, you can keep track of where you are in the list. As the user plays through the file, keep checking to see if the time has passed the next element and so on. In other words, remember where you were, and use that when you check again. If the user rewinds, check the preceding elements.
*Arguably, this isn't strictly true -- there are surely faster ways if you can make a good guess as to the probable location of the element in question. But if you don't know anything other than that the element appears somewhere in the array, it's usually the right approach.
I'm not sure if it's the best approach, but I think it'll get the job done (assuming your array is always ascending order).
- (NSNumber *) incrementalClosestLowestNumberForNumber:(NSNumber *)aNumber inArray:(NSArray *)array {
for (int i = 0; i < array.count; i++) {
if ([array[i] floatValue] == [aNumber floatValue]) {
return aNumber;
}
else if ([array[i] floatValue] > [aNumber floatValue]) {
int index = (i > 0) ? i - 1 : 0;
return array[index];
}
}
return #0;
}
Then call it like this:
NSArray * numbArray = #[#0.0, #1.2, #4.3, #5.9, #7.2, #8.0];
NSNumber * closestNumber = [self closestLowestNumberForNumber:#2.4 inArray:numbArray];
NSLog(#"closest number: %#", closestNumber);
I'm not sure if someone else knows a special way that is much faster.
Based on some of the other answers / comments, I came up with this, perhaps one of them can point out if a whole is somewhere.
- (NSNumber *) quartalClosestLowestNumberForNumber:(NSNumber *)compareNumber inArray:(NSArray *)array {
int low = 0;
int high = array.count - 1;
NSNumber * lastNumber;
int currentIndex = 0;
for (currentIndex = low + (high - low) / 2; low <= high; currentIndex = low + (high - low) / 2) {
NSNumber * numb = array[currentIndex];
if (numb.floatValue < compareNumber.floatValue) {
low = currentIndex + 1;
}
else if (numb.floatValue > compareNumber.floatValue) {
high = currentIndex - 1;
}
else if (numb.floatValue == compareNumber.floatValue) {
return numb;
}
lastNumber = numb;
}
if (lastNumber.floatValue > compareNumber.floatValue && currentIndex != 0) {
lastNumber = array[currentIndex - 1];
}
return lastNumber;
}
I'm really bored right now, so I'm trying to test the fastest method. Here's how I did it.
NSMutableArray * numbersArray = [NSMutableArray new];
for (int i = 0; i < 100000; i++) {
float floater = i / 100.0;
[numbersArray addObject: #(floater)];
}
// courtesy #RobMayoff
NSDate * binaryDate = [NSDate date];
NSNumber * closestNumberBinary = [self binaryClosestLowestNumberForNumber:#4.4 inArray:numbersArray];
NSLog(#"Found closest number binary: %# in: %f seconds", closestNumberBinary, -[binaryDate timeIntervalSinceNow]);
// The Quartal Version
NSDate * quartalDate = [NSDate date];
NSNumber * closestNumberQuartal = [self quartalClosestLowestNumberForNumber:#4.4 inArray:numbersArray];
NSLog(#"Found closest number quartal: %# in: %f seconds", closestNumberQuartal, -[quartalDate timeIntervalSinceNow]);
// The incremental version
NSDate * incrementalDate = [NSDate date];
NSNumber * closestNumberIncremental = [self incrementalClosestLowestNumberForNumber:#4.4 inArray:numbersArray];
NSLog(#"Found closest number incremental: %# in: %f seconds", closestNumberIncremental, -[incrementalDate timeIntervalSinceNow]);
And here's the output:
Found closest number binary: 4.4 in: 0.000030 seconds
Found closest number quartal: 4.4 in: 0.000015 seconds
Found closest number incremental: 4.4 in: 0.000092 seconds
And another test case:
Found closest number binary: 751.48 in: 0.000030 seconds
Found closest number quartal: 751.48 in: 0.000016 seconds
Found closest number incremental: 751.48 in: 0.013042 seconds

Calculating percent for 1,000s of objects slow in xcode

can anyone suggest a faster approach to the following:
I have an array of 5,000 managed objects (faulted) (an array of car.h objects)
Each object has a set of items (toCarParts.h). This set can have any number of objects.
Now i want to sort these out by the most matches in my search query carpart array.
I search for wheel, seat, window, mirror.
The method will go through each car and find the closest match, and calculate a percentage. So if car a has wheel, seat, window, mirror, mat, tire, wiper, pipe --> the % should be 50%. (Matched 4/8 parts.
This is simple enough, but the problem is with 5,000 items the search takes a long time (even using coredata).
The logic i am using goes something like: (Pseudocode)
For each Car*car in array.
NSMutableArray *x=[car tocarparts]allobjects];
For the count of objects in x.
Carpart*part=objectatindex...i.
If the name of this matches one of my parts
add a count to my counter.
At the end of the loop counter/[x count] =%.car.percent=%.
There has to be a better way, any suggestions? (I think its the dividing and checking each part that takes forever.
Thank you in advance.
Edited, added code below:.
-(NSMutableArray*)calculatePercentagePerFind:(NSMutableArray*)CarArray:(NSMutableArray*)partsArray{
NSArray*defaultParts =[NSArray arrayWithArray:[[[HelperMethods alloc]init]getObjectUserDefault:#"AvailableDefaultParts"]];
int lowestPercentMatchInt=[[[HelperMethods alloc]init]getIntegerUserDefault:#"lowestPercentageMatch"];
NSMutableArray*partsFromCarArray=[[NSMutableArray alloc]init];
NSMutableArray*returnArray=[[NSMutableArray alloc]init];
NSMutableArray *partsWithDefaultParts =[NSMutableArray arrayWithArray:partsArray];
[partsWithDefaultParts addObjectsFromArray:defaultParts];
for (int i=0; i<[CarArray count]; i++) {
double matchCount=0;
Car *CarResult =(Car*)[CarArray objectAtIndex:i];
//Check if it will at least be 30% match
double number1 = [partsWithDefaultParts count];
number1 =(number1/[CarResult.numberOfParts doubleValue])*100;
if (number1>lowestPercentMatchInt) {
partsFromCarArray =[NSMutableArray arrayWithArray:[[CarResult toParts]allObjects]];
NSMutableArray *faultedParts=[[NSMutableArray alloc]init];
for (int i =0; i<[partsFromCarArray count]; i++) {
CarPart*part = (CarPart*)[partsFromCarArray objectAtIndex:i];
[faultedParts addObject:part.name];
}
// for each part in the Car
for (NSString *partInCar in partsWithDefaultParts){
//if the search parts contain that part, add one to count
if ([faultedParts containsObject:partInCar]) {
matchCount++;
}
}
//Calculate percent match
double percentMatch = matchCount;
percentMatch =(percentMatch/[CarResult.numberOfParts doubleValue])*100;
//if at least 30%(user default) then add the percent match to Car result
if (percentMatch >lowestPercentMatchInt) {
if (percentMatch>100) {
CarResult.percentMatch = [NSNumber numberWithDouble:100.00];
}else{
CarResult.percentMatch = [NSNumber numberWithDouble:percentMatch];
}
[returnArray addObject:CarResult];
}
}
}
NSLog(#"Percent Matched Cars = %i",[returnArray count]);
return [self arrangeByHighestPercentMatch:returnArray];
}
Try this, which I believe will minimize the strain on core data.
NSSet *selectionSet; // contains the selected parts
NSPredicate *filter = [NSPredicate predicateWithFormat:
#"self IN %#", selectionSet];
float percentageSum = 0;
NSSet *parts;
for (Car *car in fetchedObjects) {
parts = car.parts; // so the relationship is retrieved only once
percentageSum +=
[parts filteredSetUsingPredicate:predicate].count*1.0f
/ (parts.count*1.0f);
}
return percentageSum/fetchedObjects.count;
This would average out the percentages across all cars. There are other methods to weigh the parts differently in the aggregate.
It is not clear from your question, but if you do not need a total percentage but one percentage for each car there would be no need to loop through all cars - you could just calculate the percentage on the fly when displaying it (e.g. with a transient property).

How to Create a Dynamic CGPoint** array

I have a few maps (tilemaps made with Tiled QT) and I would like to create a CGpoint **array based on the objects groups of those maps (I call them Waypoints).
Each maps can have a few set of waypoints that I call path.
//Create the first dimension
int nbrOfPaths = [[self.tileMap objectGroups] count];
CGPoint **pathArray = malloc(nbrOfPaths * sizeof(CGPoint *));
Then for the second dimension
//Create the second dimension
int pathCounter = 0;
while ((path = [self.tileMap objectGroupNamed:[NSString stringWithFormat:#"Path%d", pathCounter]])) {
int nbrOfWpts = 0;
while ((waypoint = [path objectNamed:[NSString stringWithFormat:#"Wpt%d", nbrOfWpts]])) {
nbrOfWpts++;
}
pathArray[pathCounter] = malloc(nbrOfWpts * sizeof(CGPoint));
pathCounter++;
}
Now I want to fill up the pathArray
//Fill the array
pathCounter = 0;
while ((path = [self.tileMap objectGroupNamed:[NSString stringWithFormat:#"Path%d", pathCounter]]))
{
int waypointCounter = 0;
//Get all the waypoints from the path
while ((waypoint = [path objectNamed:[NSString stringWithFormat:#"Wpt%d", waypointCounter]]))
{
pathArray[pathCounter][waypointCounter].x = [[waypoint valueForKey:#"x"] intValue];
pathArray[pathCounter][waypointCounter].y = [[waypoint valueForKey:#"y"] intValue];
NSLog(#"x : %f & y : %f",pathArray[pathCounter][waypointCounter].x,pathArray[pathCounter][waypointCounter].y);
waypointCounter++;
}
pathCounter++;
}
When I NSLog(#"%#",pathArray), it shows me the entire pathArray will the x and y.
HOWEVER 2 problems :
The y value is never correct (the x value is correct and my tilemap.tmx is correct too)
<object name="Wpt0" x="-18" y="304"/> <-- I get x : -18 and y :336 with NSLog
<object name="Wpt1" x="111" y="304"/> <-- I get x : 111 and y :336
<object name="Wpt2" x="112" y="207"/> <-- I get x : 112 and y :433
I get a EX_BAD_ACCESS at the end of the NSLog
EDIT
Thank you about the NSLog(%#) concerning CGPoint.
However, I get the y value with this line (in the ugly loop):
NSLog(#"x : %f & y : %f",pathArray[pathCounter][waypointCounter].x,pathArray[pathCounter][waypointCounter].y);
First of all, you can't NSLog CGPoint like that because it is not an object. %# expects an objective c object to send a description message to.
Secondly, you can use an NSValue wrapper and then use NSMutableArray as you would with any other object. Is there a reason you don't want to do that? You can add arrays inside other arrays as you are doing.
Regarding the first problem:
The y value is never correct (the x value is correct and my tilemap.tmx is correct too)
Have you noticed that if you add the y values from tile map and from NSLog they always add up to 640? Then you better check if tilemap y-coordinate is top-to-bottom as oppose to CGPoint's bottom-to-top. Then you can always do 640 - y to convert the y-coordinate between the two coordinate systems.

Resources