2013-06-03 13 views
16

Muszę podjąć decyzję w oparciu o dość duży zestaw ośmiu współzależnych warunków.Jak zaimplementować macierz decyzyjną w 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 

Każdy z warunków od A do H mogą być prawdziwe (1), fałszywe (0) lub nie dotyczy (-) do podjęcia decyzji.

Więc z danym wejściem

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

powinna ocenić do Decision02.

Decyzje są jednoznaczne, więc z dowolnego zestawu warunków wejściowych jasno wynika, która decyzja musi zostać podjęta (aw przypadku, który nie jest objęty matrycą decyzyjną, zostanie zgłoszony wyjątek).

Deweloper, który pracował przede mną przy tym projekcie, próbował wdrożyć to jako 500-wierszowy zagnieżdżony - jeśli behemot, który oczywiście jest błędny jak diabli i nie da się go utrzymać.

Poszukałem więc najlepszego sposobu na wdrożenie takiego elementu logiki i trafiłem na tablice decyzyjne/tabele przeglądowe/tabele sterujące.

Znalazłem wiele generatorów stołowych decyzja, ale nie jeden kawałek kodu na temat sposobu wykonania decyzji proces :(

co mogę zrobić tabelę decyzyjną w podstawowej bazie danych MSSQL, lub w Kod lub xml, lub co trzeba. Muszę tylko kilka wskazówek, w jaki sposób zaimplementować to w ogóle.

Co jest najlepszą praktykę w celu realizacji tej logiki coś zupełnie innego?

+0

Boolean nullable jest, gdzie chciałbym zacząć ... bool? Może być prawdziwe fałsz lub null – Sayse

+0

@Sayse By - on nie znaczy, że jest ważny, np. Może być 1 lub 0. –

Odpowiedz

6

Można to zrobić z tablicami FUNC.

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; }; 

Teraz można umieścić matrycę do słownika tak:

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}); 

Wreszcie dla każdej danej tablicy wejściowej:

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" 

Powinno to prawdopodobnie trochę więcej kontroli (np sprawdzanie że tablica wejściowa ma poprawny rozmiar), ale powinna dać ci pewien pomysł. Korzystanie z Funcs zapewnia również większą elastyczność w przypadku uzyskania czwartego stanu.

+1

Nazwałeś zarówno wynik "string", jak i "bool" " – jszigeti

+1

Dziękuję, naprawiłem to.I to powinno być Func zamiast Func , naprawiłem to również. –

+0

To działa jak urok! –

2

ja? słownik? tablica wielowymiarowa? "użyjemy tablicy 2D (Dictionary<TKey, TValue> w naszym przypadku) z bool? - zanotuj ? dla Nullable<bool>, która pozwala na 3 stany: true, false i null. Twoja wartość null może reprezentować "żadnego wpływu" ...

Zdefiniowane tablicy:

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

Następnie można robić takie rzeczy jak:

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

return result; 
+1

Uruchom bool za pomocą false, i spraw, aby '&' z fałszem zawsze otrzymujesz fałsz ... – Aristos

+0

You ' no dobra, to był tylko przykład tego, co można zrobić, a nie CO. Zaktualizuję kod taki sam do OR. – Haney

+1

Ok, teraz rozumiesz, że na pierwszym prawdziwym, pozostanie prawdą dla reszty pętli, a ty albo jesteś tym, co wygrałeś -default false, jeden true all true- albo nie. Więc na pierwszym prawdziwym, po prostu wróć do prawdy, nie kontynuuj. – Aristos

0

Można to zrobić w kilku liniach i utworzyć kalkulator binarny. Tak więc w poniższym przykładzie wyniki = 182 niż decyzja D (lub co każdy). Poniżej, linie z twoimi decyzjami i wynikami będą różne sumy.

Oto strona internetowa, która przechodzi przez Binary [http://electronicsclub.info/counting.htm] dzięki google.

Przykładowo 10110110 binarnie równa 182 dziesiętny: wartość cyfry: 128 64 32 16 8 4 2 1
liczby binarnej 1 0 1 1 0 1 1 0
wartość dziesiętny: 128 + 0 + 32 + 16 + 0 + 4 + 2 + 0 = 182

1

Możesz mieć klasę decyzyjną reprezentowaną dwoma polami bajtowymi. Pierwszy bajt określi, które warunki są prawdziwe lub fałszywe. Drugi bajt określi, które warunki są istotne. Dodatkowo można zdefiniować funkcję, która określa, czy bajt wejściowy pasuje do obiektu.

Na tej podstawie można utworzyć klasę macierzy, która opakowuje listę decyzji, a następnie używa LINQ do przeszukania listy w celu podjęcia decyzji zgodnej z wprowadzonymi danymi.

Można masz decyzję klasy jak ten

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 
    } 
} 

Więc, obiekt dla Decision01 można określić jako

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

Następnie klasa Decyzja Matrix może być wykonane jak to

class DecisionMatrix 
{ 
    List<Decision> decisions; 

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

Może również pomóc utworzyć klasę wejściową, która otacza bajt. Gdy tworzysz obiekt wejściowy za pomocą pól A-H, tworzony jest bajt, aby dopasować te pola.

2

Tak to zrobię, z moją miłością do LINQ.

pierwszy, matryce są IEnumerable<IEnumerable<bool?>> i true oznacza 1, false, 0 i null nieokreślony.

Następnie należy podać IEnumerable<bool>, które chcesz sprawdzić. Oto funkcja:

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(); 
} 

(Jest to metoda rozszerzenie, umieścić go w static class :))

1

można zaimplementować macierz decyzja co do słownika, jak pokazano poniżej i zapytań na matrycy znaleźć dopasowanie . Użyłem string.join do przekształcenia tablicy w ciąg znaków. Użyto również "-" w macierzy jako 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);