【问题标题】:Non-boolean "truth table" creation非布尔“真值表”创建
【发布时间】:2015-04-02 01:06:43
【问题描述】:

我有以下问题:我需要创建一个表,它是来自集合的值的组合。集合中元素的基数是未知的,并且可能因集合而异,值的域是未知的,并且也可能因集合而异。集合中的元素是非负的,至少有两个元素在一个集合中。 下面是一个例子:

  • SET_A = { 0, 1, 2 }
  • SET_B = { 0, 1 }
  • SET_C = { 0, 1 }

结果应包含以下行(顺序不是约束):

表格:

  • | 0 0 0 |
  • | 0 0 1 |
  • | 0 1 0 |
  • | 0 1 1 |
  • | 1 0 0 |
  • | 1 0 1 |
  • | 1 1 0 |
  • | 1 1 1 |
  • | 2 0 0 |
  • | 2 0 1 |
  • | 2 1 0 |
  • | 2 1 1 |

有人知道这个问题背后的数学是什么吗?我试图查看多集问题、逻辑表、组合学。我发现的许多定义与我的问题有相似之处,但我无法在迄今为止访问的文献中隔离任何内容。一旦有了参考定义,我就可以考虑对其进行编码,但现在我迷失在递归函数和可怕的数组索引游戏中。谢谢。

编辑:已在以下位置提出问题: C# Permutation of an array of arraylists?

【问题讨论】:

  • 我不确定您发布的套装与您的桌子有什么关系。你能解释一下这种关系吗?
  • @GeorgeMauer 表包含所有可能设置值的所有组合。
  • 我不太了解 C#,但在 python 中,这是生成器/产量使用的完美示例。 yield 存在于 C# 中;可能有一种方法可以使用 yield 构造所需的表。 python中的示例:pastebin.com/zveXyd0S
  • @revani 哇,它在 python 中效果很好!

标签: c# logic combinatorics multiset


【解决方案1】:

编辑:抱歉,昨晚不得不跑。对于任意维度,您可能必须使用递归。可能有一种方法可以不用它,但使用递归是最直接的。以下内容未经测试,但应该是正确的。

IEnumerable<int[]> getRows(int[][] possibleColumnValues, int[] rowPrefix) {
    if(possibleColumnValues.Any()) { //can't return early when using yield
        var remainingColumns = possibleColumnValues.Skip(1).ToArray();
        foreach(var val in possibleColumnValues.First()) {
           var rowSoFar = rowPrefix.Concat(new[]{val}).ToArray(); 
           yield return getRows(remainingColumns rowSoFar);
        }
    }
}

用法:

    getRows(new [][] {
                 new [] {0,1,2},
                 new [] {0,1},
                 new [] {0,1},
    }, new int[0]);

【讨论】:

  • 哇,好吧,它可以工作,但是否可以将此功能扩展到数组集合? (从pos1到posN是动态创建的),我有一个动态的数组集合,不知道会来多少。我试过这个:pastebin.com/jV6pfMdh
  • @user3200743 抱歉,我昨晚不得不用完。检查我的编辑。我认为它比公认的答案简单得多。
  • 我喜欢它;)我找到了另一个可用的递归解决方案,但无论如何我可能会选择你的。 6行代码,我喜欢。祝你有美好的一天。
【解决方案2】:

您要寻找的是组合数学。此外,集合中元素的域是什么并不重要。只要能枚举出来,问题就和0到集合基数的数字一样。

要枚举所有选项,有一个索引向量,并在每次迭代后递增第一个索引。如果它溢出,设置为 0 并增加第二个索引,等等。

【讨论】:

  • 组合学是一个相当大的分支,我迷失在定义的狂野森林中。关于你的解决方案,你的索引是什么意思?它是集合中元素的索引(如果您考虑数组表示)还是其他东西(可能与表本身有关)
【解决方案3】:

任务是打印排列。你似乎挖得更深了。它与元素的性质无关。

【讨论】:

  • 因为我不知道集合的数量,也不知道其中的元素数量。我发现很难实现(当这两个约束不再成立时,我无法轻松定义构建表的规则)。我拿了第一组,然后我尝试考虑第二组,然后是第三组来构建排列,但是我怎么能停下来呢?我尝试了递归函数方法,但终止条件是什么? (或者也许我累了,需要睡觉;))
  • @user3200743 查看我的解决方案。终止的条件是没有更多的列需要处理
【解决方案4】:

以下内容不是为了效率而写的(无论是空间还是速度)。我们的想法是让基本算法通俗易懂。我会留给你来提高空间和时间效率。

基本思想是认识到n 列表的所有组合,只是n-1 列表的所有组合加上第一个列表的每个元素。在这一点上,这是一个非常简单的递归函数。

public static IEnumerable<int[]> Permute( params IEnumerable<int>[] sets )
{
    if( sets.Length == 0 ) yield break;
    if( sets.Length == 1 ) 
    {
        foreach( var element in sets[0] ) yield return new[] { element };
        yield break;
    }

    var first = sets.First();

    var rest = Permute( sets.Skip( 1 ).ToArray() );

    var elements = first.ToArray();

    foreach( var permutation in rest )
    {
        foreach( var element in elements )
        {
            var result = new int[permutation.Length + 1];
            result[0] = element;
            Array.Copy( permutation, 0, result, 1, permutation.Length );
            yield return result;
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    • 1970-01-01
    相关资源
    最近更新 更多