【问题标题】:Finding all combinations from sets of possibilities从可能性集合中找到所有组合
【发布时间】:2013-10-09 00:59:45
【问题描述】:

我有多组数组,其中包含附加的数组,这些数组附加了用于计算数学的值。为了找到这些东西的最佳组合,我需要从这些数组中进行混合和匹配。我已经看到与此类似的“解决方案”,但它们通常是 1 阵列深,没有真正的组合/可能性。举个例子吧。

我有集合 A、B 和 C。集合 A 包含 Aa、Ab、Ac 和 Ad。 Aa 包含一组值。为其他人推断出来。 Aa 只能与 Ba 和 Ca 进行比较。如何编写程序来查找所有组合(即 Aa、Ab、Cc、Bd 与 Ba、Cb、Ac、Bd 等相比),以便我可以比较每个组合的数学以找到最佳组合?注意:这只是一个例子,具体3组4组4组不需要,需要能够扩展。

现在我知道我没有为我的变量使用非常有意义的名称,但如果给出的任何代码中确实有有意义的名称,我将不胜感激(我真的不想在代码中围绕 x 和 c 的变量) .

【问题讨论】:

标签: c# arrays combinations permutation


【解决方案1】:

接受的答案似乎是正确的,但在 C# 中进行笛卡尔积是一种非常奇怪的方法。如果您有给定数量的序列,您可以像这样惯用地采用他们的笛卡尔积:

    var aList = new[] { "a1", "a2", "a3" };
    var bList = new[] { "b1", "b2", "b3" };
    var cList = new[] { "c1", "c2", "c3" };
    var product = from a in aList
                  from b in bList
                  from c in cList
                  select new[] { a, b, c };

    foreach (var p in product)
        Console.WriteLine(string.Join(",", p));

如果您有任意多个序列需要获取他们的笛卡尔积,那么您可以这样做:

static class Extensions
{
  public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
    this IEnumerable<IEnumerable<T>> sequences) 
  { 
    IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() }; 
    return sequences.Aggregate( 
      emptyProduct, 
      (accumulator, sequence) => 
        from accseq in accumulator 
        from item in sequence 
        select accseq.Concat(new[] {item})); 
  }
}

然后:

    var aList = new[] { "a1", "a2", "a3" };
    var bList = new[] { "b1", "b2", "b3" };
    var cList = new[] { "c1", "c2", "c3" };
    var lists = new[] { aList, bList, cList };
    var product = lists.CartesianProduct();
    foreach (var p in product)
        Console.WriteLine(string.Join(",", p));

http://ericlippert.com/2010/06/28/computing-a-cartesian-product-with-linq/

我的回答

Generating all Possible Combinations

更多关于这个问题的讨论。

【讨论】:

  • 感谢您的替代答案。不过,使用其他列出的答案有什么真正的问题吗?除了它不适用于随机输入量之外?
  • 哦,哇,我不知道你可以那样做连接。来自 SQL 背景,在没有连接运算符的情况下执行此操作几乎似乎“错误”,但如果它有效......
【解决方案2】:

假设您使用的是支持 LINQ 的 C# 版本:

static void Main(string[] args)
    {
        // declare some lists
        var aList = new string[] { "a1", "a2", "a3" };
        var bList = new string[] { "b1", "b2", "b3" };
        var cList = new string[] { "c1", "c2", "c3" };

        // do the equivalent of a SQL CROSS JOIN
        var permutations = aList
            .Join(bList, a => "", b => "", (a, b) => new string[] { a, b })
            .Join(cList, ab => "", c => "", (ab, c) => new string[] { ab[0], ab[1], c });

        // print the results
        Console.WriteLine("Permutations:");
        foreach (var p in permutations)
            Console.WriteLine(string.Join(", ", p));
    }

使用 lambda 表达式将字符串指向空字符串的 Join 调用导致 Join 函数将字符串视为相等,模拟 SQL CROSS JOIN。

【讨论】:

  • 哦,抱歉,我没有注意到您想要多个深度数组。这究竟是如何工作的?你说每个子数组应该只用它的“兄弟姐妹”生成排列?然后这些排列将如何相互排列?
  • 好吧,举一个非常具体的列表示例(我仍然会保持简单)...集合 A 包含 Aa、Ab 和集合 B 包含 Ba、Bb。 Aa 包含数字 4,0,1,1。抗体:10,1,0,1。巴:15,0,0,0。 BB:20,0,0,8。我们要说的最好的集合将只涉及第一个和最后一个数字,即基于我拥有的另一组数字的乘数。对于一组特定的数字,最好的结果是 Ba 和 Bb,而另一组数字是 Aa 和 Bb。所以我需要为每个组合选择一个 suba 和 subb 。只有一个suba,一个subb,等等。清楚吗?
  • 刚刚运行了您的代码。很不错。谢谢你。我可以根据需要调整它。
  • 这似乎是正确的,但这是在 LINQ 中进行笛卡尔积的奇怪方式。请参阅我的答案以了解如何以惯用方式这样做。
  • 我还注意到,这个答案并没有解决原始问题的主要困难:数组的数量不固定。 SelectMany 和 Join 均未解决;正如我在回答中指出的那样,您必须编写一个可以采用任意多个序列的通用运算符。
猜你喜欢
  • 2017-08-27
  • 2012-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-10
  • 2018-06-08
相关资源
最近更新 更多