2013-05-16 13 views
10

Chcę rozwiązać warunkową równanie w iOS:jak rozwiązać równanie warunkowe w iOS

Równanie uzyskać z bazy danych jest w formacie NSString, na przykład:

if((height > 0), (weight+ 2), (weight-1)) 

Według naszego rozumienia , jeśli przeanalizuję powyższy ciąg i oddzielę warunek height>0, będzie on w formacie NSString. Ale do oceny, w jaki sposób przekonwertować ciąg do instrukcji warunkowej?

Gdy instrukcja warunkowa uzyskuje się równanie może być rozwiązywane przez przekształcenie go w trójskładnikowym poniższego równania:

Bool status; 

NSString *[email protected]” height>0”; 

If(condition)    //But condition is treated as a string and not as a conditional statement. 
{ 
    status=True; 
} 
else 
{ 
    status=False; 
} 

Return status ? weight+ 2 : weight-1;` 

także równania może się dynamicznie zmieniać, tak, że nie może być zakodowana. W skrócie, jak rozwiązać to równanie, które dostaję jako NSString.

Dziękuję za cierpliwość!

+0

Pracujesz z danymi na żywo w istniejącym formacie lub można użyć dowolnego format, który chcesz? – tia

+0

powiązane z http://stackoverflow.com/questions/2550897/eval-for-objective-ccode – Daniel

+0

W żaden sposób 'height' i' weight' nie będą zmienną do porównania. – rptwsthi

Odpowiedz

4

Będziesz musiał napisać własnego tłumacza lub znaleźć taki, który obsługuje tego rodzaju wyrażeń.

Pierwsza część (stan) może być oceniona przez NSPredicate. W drugiej części (obliczenia) będziesz potrzebował oceny wyrażenia matematycznego. Wypróbuj to https://github.com/davedelong/DDMathParser. Być może możesz zrobić oba z DDMathParser, ale nie jestem pewien.

5

DDMathParser autor tutaj ...

Aby rozwinąć na Jonathan's answer, oto jak można to zrobić w całości DDMathParser. Jednak, aby przeanalizować ciąg znaków jako taki, musisz zrobić dwie rzeczy.

Po pierwsze, musisz utworzyć funkcję if:

DDMathEvaluator *evaluator = [DDMathEvaluator sharedMathEvaluator]; 
[evaluator registerFunction:^DDExpression *(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError *__autoreleasing *error) { 
    if ([args count] == 3) { 
     DDExpression *condition = [args objectAtIndex:0]; 
     DDExpression *resultExpression = nil; 
     NSNumber *conditionValue = [condition evaluateWithSubstitutions:vars evaluator:eval error:error]; 
     if ([conditionValue boolValue] == YES) { 
      resultExpression = [args objectAtIndex:1]; 
     } else { 
      resultExpression = [args objectAtIndex:2]; 
     } 
     NSNumber *result = [resultExpression evaluateWithSubstitutions:vars evaluator:eval error:error]; 
     return [DDExpression numberExpressionWithNumber:result]; 
    } 
    return nil; 

} forName:@"if"]; 

Stwarza funkcję if(), która przyjmuje trzy parametry. W zależności od tego, jak oceniany jest pierwszy parametr, następuje albo wynik drugiego, albo trzeciego parametru.

Kolejną rzeczą, którą musisz zrobić, to powiedzieć oceniającemu, co to znaczy height i weight. Ponieważ nie zaczynają się od znaku $, interpretowane są jako funkcje, a nie zmienne. Jeśli zaczęli z $, to byłoby tak proste, jak oceny to tak:

NSString *expression = @"if(($height > 0), ($weight+ 2), ($weight-1))"; 
NSDictionary *variables = @{@"height" : @42, @"weight" : @13}; 
NSNumber *result = [expression evaluateWithSubstitutions:variables evaluator:evaluator error:nil]; 

Jednak od oni NIE początek z $, są funkcje, co oznacza, że ​​trzeba powiedz oceniającemu, na czym polega funkcja.Można to zrobić poprzez stworzenie funkcji zarówno height i weight, tak jak to zrobiliśmy dla if:

[evaluator registerFunction:^DDExpression *(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError **error) { 
    return [DDExpression numberExpressionWithNumber:@42]; 
} forName:@"height"]; 

Alternatywnie, można zrobić to nieco bardziej dynamiczny i użyć bloku functionResolver z DDMathEvaluator, który to blok, który zwraca blok (woooooo) i będzie wyglądać następująco:

NSDictionary *values = @{@"height": @42, @"weight": @13}; 
[evaluator setFunctionResolver:^DDMathFunction(NSString *name) { 
    DDMathFunction f = ^(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError **error) { 
     NSNumber *n = [values objectForKey:name]; 
     if (!n) { n = @0; } 
     return [DDExpression numberExpressionWithNumber:n]; 
    }; 
    return f; 
}]; 

z tych dwóch elementów w miejscu (rejestrujących if i dostarczenie wartości height i weight), można zrobić:

NSString *expression = @"if((height > 0), (weight+ 2), (weight-1))"; 
NSNumber *result = [expression evaluateWithSubstitutions:nil evaluator:evaluator error:nil]; 

... i odbierz prawidłowy wynik @15.

(mam plany, aby umożliwić DDMathParser nieznane funkcje spadać z powrotem do określonych wartości zmiennych, ale nie całkiem wykończony go jeszcze)

+0

Podoba mi się początek odpowiedzi! :-) – Amar

+0

Sposób podejścia w przypadku, gdy równanie ma wywołanie funkcji Ex: 'if (xyz == 0, if (abc <0, 270, 90), atan (xyz/abc) * 180/_pi)'? – Amar

+0

@Amar, o ile zdefiniujesz, czym są '_pi',' xyz' i 'abc', które będą działać poprawnie. 'atan' jest wbudowaną funkcją. (Ale jeśli nazwałeś to 'pi' zamiast' _pi', nie będziesz musiał tego definiować. ['Pi' jest również wbudowaną funkcją] (https://github.com/davedelong/DDMathParser/ wiki/Built-in-Functions). –