Таблица правды как ключи для словаря - PullRequest
3 голосов
/ 09 сентября 2010

У меня есть шесть логических флагов, которые не зависят друг от друга, поэтому существует 64 возможных комбинации. Эти флаги должны определять значение некоторой строки. Эта строка может иметь семь разных значений. Я думаю, что реализовать это как большое if-выражение - плохая идея, поэтому я подумал о создании таблицы истинности, где каждая комбинация определяет конкретный результат:

Key            Value
0,0,0,0,0,0 -> "A"
0,0,0,0,0,1 -> "A"
0,0,0,0,1,0 -> "B"
0,0,0,0,1,1 -> "C"
0,0,0,1,0,0 -> "A"
...

Это замечательно похоже на словарь, но какова будет лучшая реализация ключа (в C #)? Наименьший возможный ключ будет byte, в который я маскирую опции. Однако это не улучшит читабельность моего кода.

Есть ли другие решения для этого?

Ответы [ 7 ]

7 голосов
/ 09 сентября 2010

Вы можете представить 6 параметров bool как перечисление с FlagsAttribute и полагаться на удобочитаемость имен ваших перечислений.

Изменить, например:

[Flags]
enum MyFlagSet : byte
{
    NoFlags = 0,
    Flag1 = 1 << 0,
    Flag2 = 1 << 1,
    Flag3 = 1 << 2,
    Flag4 = 1 << 3,
    Flag5 = 1 << 4,
    Flag6 = 1 << 5
};

Dictionary MyDictionary = new Dictionary<MyFlagSet, string>()
                          {
                              {MyFlagSet.NoFlags, "Q"},
                              {MyFlagSet.Flag1 | MyFlagSet.Flag2, "A"},
                              {MyFlagSet.Flag3 | MyFlagSet.Flag5 | MyFlagSet.Flag6, "B"}
                          };
3 голосов
/ 12 марта 2012

Это старый вопрос - и на него ответили, но, поскольку я столкнулся с этим, когда сам искал решение, вот мое мнение о нем.

public interface ITruthTable<in T1, in T2, in T3, in T4>
{
    bool GetValue(T1 obj1, T2 obj2, T3 obj3, T4 obj4);
}
public static class TruthTable
{
    private interface IMutableTable
    {
        void AddRow(bool v1, bool v2, bool v3, bool v4, bool result = false);
    }

    private sealed class Table<T1, T2, T3, T4>: ITruthTable<T1, T2, T3, T4>, IMutableTable
    {
        private readonly Func<T1, bool> _column1;
        private readonly Func<T2, bool> _column2;
        private readonly Func<T3, bool> _column3;
        private readonly Func<T4, bool> _column4;

        private readonly List<bool[]> _rows = new List<bool[]>();
        private readonly List<bool> _results = new List<bool>();

        private readonly bool _default;

        public Table(Func<T1, bool> column1, Func<T2, bool> column2, Func<T3, bool> column3, Func<T4, bool> column4, bool defaultValue)
        {
            _column1 = column1;
            _column2 = column2;
            _column3 = column3;
            _column4 = column4;

            _default = defaultValue;
        }

        #region IMutableTable<T1,T2,T3,T4> Members

        void IMutableTable.AddRow(bool v1, bool v2, bool v3, bool v4, bool result)
        {
            _rows.Add(new bool[4]);
            var row = _rows[_rows.Count - 1];
            row[0] = v1;
            row[1] = v2;
            row[2] = v3;
            row[3] = v4;

            _results.Add(result);
        }

        #endregion

        #region ITruthTable<T1,T2,T3,T4> Members

        public bool GetValue(T1 obj1, T2 obj2, T3 obj3, T4 obj4)
        {
            var v1 = _column1(obj1);
            var v2 = _column2(obj2);
            var v3 = _column3(obj3);
            var v4 = _column4(obj4);

            for (int i = 0; i < _rows.Count; i++)
            {
                var row = _rows[i];
                if ((row[0] == v1) && (row[1] == v2) && (row[2] == v3) && (row[3] == v4))
                    return _results[i];
            }

            return _default;
        }

        #endregion
    }

    public static ITruthTable<T1, T2, T3, T4> Create<T1, T2, T3, T4>(Func<T1, bool> column1, Func<T2, bool> column2, Func<T3, bool> column3, Func<T4, bool> column4, bool defaultValue = false)
    {
        return new Table<T1, T2, T3, T4>(column1, column2, column3, column4, defaultValue);
    }

    public static ITruthTable<T1, T2, T3, T4> Row<T1, T2, T3, T4>(this ITruthTable<T1, T2, T3, T4> table, bool v1, bool v2, bool v3, bool v4, bool result)
    {
        (table as IMutableTable).AddRow(v1, v2, v3, v4, result);
        return table;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var testTable = TruthTable.Create<bool, bool, bool, bool>
            (b => b /*Column description*/ , b => b /* Column 2 */ , b => b, b => b, defaultValue: false)
        .Row(false,                          false,                  false,  false, false)
        .Row(false,                          true,                   false,  true,  true)
        .Row(true,                           true,                   true,   false, false)
        .Row(true,                           false,                  true,   true,  true);

        var result = testTable.GetValue(false, true, false, true);
    }

Простое объяснение: предоставленные функции принимают значения для каждого столбца и преобразуют их в bools. Затем простой цикл находит первое правильное совпадение и возвращает его значение результата или возвращает указанное значение по умолчанию. последнее значение в каждом вызове .Row является результатом, если входные данные соответствуют этой строке.

Конечно, это решение для 4 общих параметров, но просто написать таблицы для большего или меньшего количества параметров, чем это. Кроме того, в приведенном выше простом случае используется сопоставление bool to bool для экстракторов значений, но в реальных приложениях может потребоваться принять объект другого типа и преобразовать его во входное значение bool для этого столбца.

Это было достаточно типично и достаточно хорошо для моих нужд, надеюсь, это поможет и кому-то еще.

1 голос
/ 09 сентября 2010

Самый простой способ:

struct KeyThing
{
  public int a,b,c,d,e,f;
}

Предпочтительным способом будет использование битовых масок.

0 голосов
/ 09 сентября 2010

Вы можете представить ваши параметры bool в виде строк, например,
«011011»
, а затем просто использовать словарь

(это может быть хорошим вариантом, если вы хотите позволить пользователю изменять сопоставления, поскольку читать строки из файла легко)

Однако, если вы будете их часто использовать, используйте перечисление flags согласно ответу Люка.

0 голосов
/ 09 сентября 2010

Если вы инкапсулируете функцию «шесть логических выражений в строку» в отдельный класс, читаемость кода будет тривиально улучшена независимо от деталей реализации.И реализация может меняться в зависимости от возникающих требований к производительности.

(я собираюсь составить название для иллюстрации.)

public static class RobotEmotionDescriptions
{
    public static string GetDescription(bool isHurting, bool isAwake, 
           bool isBrightlyLit, bool isInQuitePlace, bool isPlayingChess, 
           bool isTumpedOver)
    {
        ... // Details don’t matter.
    }
}

Так что я думаю, что растровый байт будет отличнымПервый переход к реализации.

0 голосов
/ 09 сентября 2010

Использовать битовую маску для создания целого и сохранять ваши значения в обычном хеше?

е:
0,0,0,0,0,0 = 0
0,0,0,0,0,1 = 1
0,0,0,0,1,0 = 2

, затем hash [0] = "a" и т. Д.

0 голосов
/ 09 сентября 2010

Вы можете создать перечисление с помощью FlagsAttribute , что может облегчить чтение вашего кода, но вам придется составить 64 имени!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...