2013-06-03 20 views
16

Ich muss eine Entscheidung basierend auf einem ziemlich großen Satz von 8 co-abhängigen Bedingungen treffen.Wie implementieren Entscheidungsmatrix in C#

  | A | B | C | D | E | F | G | H 
-----------+---+---+---+---+---+---+---+--- 
Decision01 | 0 | 1 | - | 1 | 0 | 1 | - | 1 
Decision02 | 1 | 0 | - | 0 | 0 | - | 1 | - 
    ... 
Decision11 | 1 | 0 | 1 | 1 | 1 | - | 1 | 1 

jeder der Bedingungen A bis H kann wahr sein, (1), falsch (0) oder nicht relevant (-) für die Entscheidung.

Also mit einem gegebenen Eingang von

A B C D E F G H 
1 0 1 0 0 1 1 1 

sollte es Decision02 bewerten.

Die Entscheidungen sind eindeutig, so dass aus jedem gegebenen Satz von Eingabebedingungen klar ist, welche Entscheidung getroffen werden muss (und in einem Fall, der nicht von der Entscheidungsmatrix abgedeckt wird, wird eine Ausnahme ausgelöst).

Der Entwickler, der vor mir an diesem Projekt gearbeitet hat, versuchte, dies als ein 500-Zeilen langes verschachtelt-wenn Ungetüm zu implementieren, das natürlich buggy ist und nicht wartbar ist.

Also suchte ich nach dem besten Weg, um ein solches Stück Logik zu implementieren, und ich bin auf Entscheidungstabellen/Nachschlagetabellen/Steuertabellen gekommen.

Ich habe eine Menge von Entscheidungstabelle Generatoren gefunden, aber nicht ein einziges Stück Code, wie der Entscheidungsprozess implementieren :(

ich die Entscheidungstabelle in der zugrunde liegenden MSSQL-Datenbank machen, oder in Code oder xml, oder was auch immer es braucht. ich brauche nur ein paar Hinweise, wie dies überhaupt zu implementieren.

Was ist die beste Praxis ist diese Logik zu implementieren? Wörterbuch? mehrdimensionales Array? etwas ganz anderes

?
+0

Nullable boolean ist, wo ich anfangen würde ... bool? Kann richtig falsch oder null sein – Sayse

+0

@Sayse By - er bedeutet, es ist nicht wichtig, zB kann es 1 oder 0 sein. –

Antwort

6

Sie es mit Arrays von Func tun könnte.

static Func<bool,bool> isTrue = delegate(bool b) { return b; }; 
static Func<bool,bool> isFalse = delegate(bool b) { return !b; }; 
static Func<bool,bool> isIrrelevant = delegate(bool b) { return true; }; 

Jetzt könnten Sie Ihre Matrix in einem Wörterbuch so:

Dictionary<string,Func<bool,bool>[]> decisionMatrix = new Dictionary<string,Func<bool,bool>[]>(); 
// 0 | 1 | - | 1 | 0 | 1 | - | 1 
matrix.Add("Decision01", new Func<bool,bool>{isFalse, isTrue, isIrrelevant, isTrue, isFalse, isTrue, isIrrelevant, isTrue}); 

schließlich für jede gegebene Eingabe-Array:

bool[] input = new bool[]{ false, true, false, true, false, true, false, true} 

string matchingRule = null; 
foreach(var pair in matrix) { 
    bool result = true; 
    for(int i = 0; i < input.Length; i++) { 
     // walk over the function array and call each function with the input value 
     result &= pair.Value[i](input[i]); 
    } 

    if (result) { // all functions returned true 
     // we got a winner 
     matchingRule = pair.Key; 
     break; 
    } 
} 

// matchingRule should now be "Decision01" 

Dies sollte wahrscheinlich einige mehr Kontrollen erhalten (zB Überprüfung dass das Eingabe-Array die richtige Größe hat), sollte Ihnen aber eine Idee geben. Wenn Sie Funcs verwenden, erhalten Sie auch mehr Flexibilität, wenn Sie einen vierten Status erhalten.

+1

Sie haben sowohl Ihr 'string' als auch Ihr' bool' "Ergebnis" – jszigeti

+1

genannt. Vielen Dank, das habe ich behoben.Und es sollte Func anstelle von Func sein, behoben, dass auch. –

+0

Das funktioniert wie ein Zauber! –

2

I verwende ein 2D Array (Dictionary<TKey, TValue> in unserem Fall) von bool? - beachte das ? für Nullable<bool>, die 3 Zustände zulässt: true, false und null. Ihre null darstellen könnte "keinen Effekt" ...

Defined Array:

var myArray = new Dictionary<char, Dictionary<int, bool?>>(); 

Dann sind Sie Dinge tun konnte, wie:

bool result = false; 
foreach (var inputPair in input) 
{ 
    // Assuming inputPair is KeyValuePair<char, int> 
    result |= myArray[inputPair.Key][inputPair.Value]; 
} 

return result; 
+1

Starten Sie den Bool mit false, und machen '&' mit dem falschen Sie immer falsch bekommen ... – Aristos

+0

Sie ' Richtig, es war nur ein Beispiel dafür, was getan werden konnte, nicht was man wörtlich tun sollte. Ich werde den Code zu einem OR statt – Haney

+1

OK aktualisieren, jetzt verstehen Sie, dass auf der ersten wahren, bleibt wahr für den Rest der Schleife, und Sie entweder ist, was Sie gewonnen haben -Standard falsch, eine wahr alle wahr- entweder nicht. Also auf der ersten wahren, nur wieder wahr, nicht weiter. – Aristos

0

Sie könnten es in ein paar Zeilen tun und einen Binärrechner erstellen. Also in einem Beispiel unten, die Ergebnisse = 182 als Entscheidung D (oder was auch immer). Die unten stehenden Punkte, die mit Ihren Entscheidungen und Ergebnissen übereinstimmen, werden alle unterschiedlich sein.

Hier ist eine Website, die über die Binary geht [http://electronicsclub.info/counting.htm] danke google.

Zum Beispiel 10.110.110 binär gleich 182 in dezimalen: Digit Wert: 128 64 32 16 8 4 2 1
Binärzahl: 1 0 1 1 0 1 1 0
Dezimalwert: 128 + 0 + 32 + 16 + 0 + 4 + 2 + 0 = 182

1

Sie können eine Entscheidungs-Klasse mit zwei Byte-Feldern darstellen lassen. Das erste Byte wird angeben, welche Bedingungen wahr oder falsch sind. Das zweite Byte bestimmt, welche Bedingungen relevant sind. Darüber hinaus können Sie eine Funktion definieren, die bestimmt, ob ein Eingabebyte mit einem Objekt übereinstimmt.

Von diesem können Sie eine Matrix-Klasse erstellen, die eine Liste von Entscheidungen umschließt und dann LINQ verwendet, um die Liste nach einer Entscheidung zu durchsuchen, die Ihrer Eingabe entspricht.

Sie können Sie die Entscheidung Klasse haben wie diese

class Decision 
{ 
    byte Conditions; 
    byte RelevantConditions; 

    bool IsMatch(byte input) 
    { 
     byte unmatchedBits = input^Conditions; //matching conditions are set to 0 
     unmatchedBits &= RelevantConditions; //Irrelevant conditions set to 0 
     return (unmatchedBits == 0); //if any bit is 1, then the input does not match the relevant conditions 
    } 
} 

So kann das Objekt für Decision01 als

Decision decision01 = new Decision() 
{ 
    Conditions   = 0x55; //01010101 in binary 
    RelevantConditions = 0xdd; //11011101 in binary 
} 

Dann Klasse Ihre Entscheidungs-Matrix definiert werden kann, wie diese

class DecisionMatrix 
{ 
    List<Decision> decisions; 

    Decision Find(byte input) 
    { 
     return decisions.Find(d => d.IsMatch(input)); 
    } 
} 
gemacht werden

Es kann auch helfen, eine Input-Klasse zu erstellen, die ein Byte umschließt. Wenn Sie ein Input-Objekt mit den A-H-Feldern instanziieren, wird ein Byte erstellt, das diesen Feldern entspricht.

2

So würde ich es machen, mit meiner Liebe zu LINQ.

Zuerst Ihre Matrizen sind ein IEnumerable<IEnumerable<bool?>> und true Mittel 1, false, 0 und null unbestimmt.

Dann übergeben Sie eine IEnumerable<bool>, die Sie überprüfen möchten. Hier ist die Funktion:

public IEnumerable<bool?> DecisionMatrix(this IEnumerable<bool> source, IEnumerable<IEnumerable<bool?>> options) 
{ 
    IList<bool> sourceList = source.ToList(); 
    return options.Where(n => n.Count() == sourceList.Count) 
     .Select(n => n.Select((x, i) => new {Value = x, Index = i})) 
     .Where(x => 
      x.All(n => !(sourceList[n.Index]^n.Value ?? sourceList[n.Index]))) 
     .FirstOrDefault(); 
} 

(Es ist eine Erweiterung Methode, steckt es in einem static class :))

1

Sie können die Entscheidungsmatrix als Wörterbuch implementieren, wie unten und Abfrage auf der Matrix gezeigt, um eine Übereinstimmung zu finden . Ich habe string.join verwendet, um das Array in eine Zeichenfolge zu konvertieren. Benutze auch das '-' in der Matrix als Regex [0 | 1].

Dictionary<string, char[]> myMatrix = new Dictionary<string, char[]>(); 
myMatrix.Add("Decision01", new char[] { '0', '1', '-', '1', '0', '1', '-', '1' }); 
myMatrix.Add("Decision02", new char[] { '1', '0', '-', '0', '0', '-', '1', '-' }); 
myMatrix.Add("Decision03", new char[] { '1', '1', '1', '0', '0', '1', '1', '1' }); 

char[] input = new char[] { '1', '0', '1', '0', '0', '1', '1', '1' }; 
var decision = (from match in myMatrix 
      where Regex.IsMatch(string.Join(string.Empty, input), 
       string.Join(string.Empty, match.Value).ToString().Replace("-", "[0|1]"), 
       RegexOptions.IgnoreCase) 
      select match.Key).FirstOrDefault(); 

Console.WriteLine(decision);