Як рэалізаваць матрыцу рашэнні ў C #

Мне трэба, каб прыняць рашэнне, грунтуючыся на даволі вялікім наборы 8 созависимых умоў.

           | 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

Кожную з умоваў ад А да Н можа быць сапраўдным (1), хлусня (0) або нерэлевантных (-) для рашэння.

Такім чынам, з улікам ўваход

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

яна павінна вылічвацца Decision02.

Рашэння адназначныя так з любога набору ўваходных умоў становіцца ясна, якое рашэнне павінна быць зроблена (і ў выпадку, калі ня ахопленага матрыцы прыняцця рашэнняў, выключэнне павінна быць кінута).

Распрацоўшчык, які працаваў перада мной на гэтым праекце спрабаваў ажыццявіць гэта як 500 лініі доўгага укладзенымі калі бегемот што, вядома, багі, як пекла, і ня рамонтапрыдатнасць.

Так што я шукаў лепшы спосаб рэалізацыі такой кавалак логікі, і я прыйшоў на прыняцце табліц/табліцах пошуку/кіраўнікі табліцамі.

Я знайшоў шмат сталоў рашэння генератараў, але ні адзін кавалак кода, пра тое, як ажыццявіць працэс прыняцця рашэнняў :(

Я магу зрабіць табліцу рашэнняў у асноўны базе дадзеных MSSQL, або ў кодзе, ці XML, ці нешта, што трэба. Мне проста трэба некалькі саветаў аб тым, як рэалізаваць гэта на ўсіх.

Што лепшая практыка для рэалізацыі гэтай логікі? Слоўнік? Мнагамерны масіў? Нешта зусім іншае?

16
@Sayse Да - ён азначае, што яго не мае значэння, напрыклад, гэта можа быць 1 або 0.
дададзена аўтар It'sNotALie., крыніца
Nullable булева, дзе я хацеў бы пачаць ... BOOL? Можа быць дакладна няўдала ці нуль
дададзена аўтар Sayse, крыніца

6 адказы

Вы можаце зрабіць гэта з масівамі Func.

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

Цяпер вы можаце змясціць вашу матрыцу ў слоўнік, як гэта:

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

Нарэшце, для кожнага зададзенага уваходнага масіва:

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"

Гэта, верагодна, атрымаць яшчэ некалькі праверак (напрыклад, праверка, што масіў ўводу мае правільны памер), але павінна даць вам некаторы ўяўленне. Выкарыстанне Funcs таксама дае вам некаторую гнуткасць у выпадку, калі вы атрымліваеце чацвёртае стан.

6
дададзена
Дзякуй, я ўсталяваў, што. І гэта павінна быць Func замест Func <> Bool, зафіксавана, што, як добра.
дададзена аўтар Jan Thomä, крыніца
Гэта працуе як шарм!
дададзена аўтар Aether McLoud, крыніца
Вы назвалі як ваш радок і ваш Bool «вынік»
дададзена аўтар jszigeti, крыніца

Гэта, як я хацеў бы зрабіць гэта, з маёй любоўю да LINQ.

First, your matrices are an IEnumerable, and true means 1, false, 0 and null indeterminate.

Then you pass an IEnumerable which you want to check. Here's the function:

public IEnumerable source, IEnumerable options)
{
    IList 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();
}

(Гэта метад пашырэння, змесціце яго ў статычны клас :))

2
дададзена

I'd use a 2D array (Dictionary in our case) of bool? - note the ? for Nullable which allows 3 states: true, false, and null. Your null could represent "no effect"...

Вызначаецца масіў:

var myArray = new Dictionary();

Тады вы маглі б зрабіць нешта накшталт:

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

return result;
2
дададзена
Запусціце BOOL з ілжывым, і зрабіць і з ілжывым вы заўсёды атрымаеце хлусня ...
дададзена аўтар Aristos, крыніца
Добра, зараз вы разумееце, што на першым праўда, заставацца верным для астатняй часткі цыклу, і вы альбо тое, што вы выйгралі -default хлусня, адзін сапраўдны ўсе true- альбо няма. Так на першым дакладна, проста вяртае ісціну, а не працягваць.
дададзена аўтар Aristos, крыніца
Вы маеце рацыю, гэта быў усяго толькі прыклад таго, што можна было б зрабіць, не тое, што рабіць даслоўна. Я буду абнаўляць код такіх жа Аня АБО замест
дададзена аўтар Haney, крыніца
Так, зноў-такі гэта ўсяго толькі прыклад таго, што можа быць зроблена ў тэорыі. Я не ў курсе, і не хачу, каб быць у курсе, яго спецыфічных логіка рашэнняў. Я толькі паказваю, як выкарыстоўваць укладзены слоўнік з дапамогай сінтаксісу индексатора.
дададзена аўтар Haney, крыніца

Вы можаце мець клас рашэння, прадстаўлены з двума палямі байтамі. Першы байт будзе паказаць, якія ўмовы з'яўляюцца праўдзівымі або ілжывымі. Другі байт будзе пазначаць, якія ўмовы актуальныя. Акрамя таго, вы можаце вызначыць функцыю, якая вызначае, калі ўваходныя байты адпавядае аб'екту.

Зыходзячы з гэтага, можна стварыць клас матрыцы, які абгортвае пералік рашэнняў, а затым выкарыстоўвае LINQ для пошуку спісу для вырашэння, якое адпавядае ўводу.

Вы можаце мець вас Decision клас, як гэта

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

Такім чынам, аб'ект для Decision01 можа быць вызначана як

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

Тады ваша рашэнне класа Матрыца можа быць зроблена, як гэта

class DecisionMatrix
{
    List decisions;

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

Ён таксама можа дапамагчы зрабіць клас Input, які абгортвае байт. Пры стварэнні асобніка аб'екта ўводу з палямі A-H, байты ствараюцца для адпаведнасці гэтых палёў.

1
дададзена

Вы можаце рэалізаваць матрыцу рашэнні ў якасці слоўніка, як паказана ніжэй, і запыт на матрыцу, каб знайсці адпаведнасць. Я выкарыстаў string.join, каб пераўтварыць масіў у радок. Таксама скарысталіся «-» ў матрыцы, як рэгулярны выраз [0 | 1].

Dictionary myMatrix = new Dictionary();
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);
1
дададзена

Вы можаце зрабіць гэта ў пару радкоў і стварыць двайковы калькулятар. Такім чынам, у прыкладзе ніжэй, вынікі = 182, чым рашэнні D (або тое, што кожны). Ніжэй лінія з вашымі рашэннямі і вынікамі будуць усе розныя вынікі.

Вось сайт, які ідзе па Binary [http://electronicsclub.info/counting.htm] дзякуй Google.

Напрыклад 10110110 ў двайковай сістэме роўна 182 у дзесятковай сістэме злічэння: Значэнне лічбы: 128 64 32 16 8 4 2 1
Двайковы нумар: 0 1 1 1 0 1 1 0
Дзесятковы значэнне: 128 + 0 + 32 + 16 + 0 + 4 + 2 + 0 = 182

0
дададзена