Reputation: 342
I've only recently jumped into the world of iphone development and objective-c, so I'm still a bit lost as to how I might implement something like this.
I have a float, and I have a list of ranges that float can fall within and the corresponding value I should return, eg:
10.0 - 14.5 : 1.0
14.5 - 17.0 : 2.0
17.0 - 23.0 : 2.5
23.0 - 32.4 : 4.0
So if my float is, say, 15.12, I want to return 2.0.
The part that makes this tricky is that the range list is quite long, and I have several such range lists that I need to choose from, any of which might need to be changed later. Simply writing a few hundred or thousand if
statements seems like an ugly solution to say the least.
Upvotes: 2
Views: 184
Reputation: 47302
Essentially what you are describing is Fuzzy Logic.
I wrote you a fuzzy logic rules class which should handle what you are wanting to do.
Features:
method
and get a string result (or nil
if it matches no rules).Add a new rule:
[logic addRule:@"2.0" forLowerCondition:14.5 forUpperCondition:17.0];
Sample output (from the code below):
Result for 15.20 is: 2.0
Here is the code implementation.....
In your Main:
FuzzyLogic *logic = [[FuzzyLogic alloc] initWithRule:@"1.0" forLowerCondition:10.0 forUpperCondition:14.5];
[logic addRule:@"2.0" forLowerCondition:14.5 forUpperCondition:17.0];
[logic addRule:@"2.5" forLowerCondition:17.0 forUpperCondition:23.0];
double input1 = 15.2f;
NSLog(@"Result for %.2lf is: %@", input1, [logic fuzzyResultForValue:input1]);
[logic release];
FuzzyLogic.h:
#import <Foundation/Foundation.h>
@interface FuzzyLogic : NSObject {
NSMutableArray *conditions;
}
- (id) initWithRule:(NSString*)result forLowerCondition:(double)lower forUpperCondition:(double)upper;
- (void) addRule:(NSString*)result forLowerCondition:(double)lower forUpperCondition:(double)upper;
- (NSString*) fuzzyResultForValue:(double)input;
@end
FuzzyLogic.m:
#import "FuzzyLogic.h"
@implementation FuzzyLogic
enum {
lowerIndex = 0,
upperIndex,
resultIndex
};
- (id) initWithRule:(NSString*)result forLowerCondition:(double)lower forUpperCondition:(double)upper {
self = [super init];
if (self != nil) {
[self addRule:result forLowerCondition:lower forUpperCondition:upper];
}
return self;
}
- (void) addRule:(NSString*)result forLowerCondition:(double)lower forUpperCondition:(double)upper {
NSArray *rule = [[NSArray alloc] initWithObjects:[NSString stringWithFormat:@"%lf",lower],[NSString stringWithFormat:@"%lf",upper],result,nil];
if (conditions == nil) {
conditions = [[NSMutableArray alloc] initWithObjects:rule,nil];
} else {
[conditions addObject:rule];
}
}
- (NSString*) fuzzyResultForValue:(double)input
{
NSString *returnable = nil;
// Find the result
for (NSArray *cond in conditions) {
double lower = [[cond objectAtIndex:lowerIndex] doubleValue];
double upper = [[cond objectAtIndex:upperIndex] doubleValue];
if ( (input >= lower && input < upper) ) {
returnable = [cond objectAtIndex:resultIndex];
break;
}
}
if (returnable == nil)
{ NSLog(@"Error: Input met no conditions!");}
return returnable;
}
@end
Upvotes: 2
Reputation: 96333
If the ranges are all adjacent, you could make a custom collection class for this, and implement it with two parallel arrays of numbers.
Each number in the first array is one end of one or two ranges:
The second array holds one fewer number; these numbers are the values to map to:
Your implementation of searching this collection would consist of comparing a requested key number to each number in the keys array and the number after it. It'd be simplest to implement a linear search, at least at first (you can optimize it later with Instruments's or Shark's guidance). For example, say this object is asked about 20:
Having found that the requested key value is within the third range, you return the third value (2.5).
Upvotes: 3