【问题标题】:How to get all possible combinations for n arrays with different number of elements?如何获得具有不同元素数量的n个数组的所有可能组合?
【发布时间】:2014-06-03 10:26:21
【问题描述】:

我有一些在编程时未知的数组,可能是 3 或 4 或 7 ...每个数组都有一些元素,即

a={1 2 3 4}
b={6 7 5 2 1}
c={22 4 6 8 4 8 5 4}
d={....}
e, f, g, ...

我想通过从每个数组中采样一个数字来获得所有可能的组合,例如,一种情况是我从 a 中选择“1”,从 b 中选择“7”,从 c 中选择第一个“8”,d[3] , e[5],... 使“1,7,8,d[3],e[5],...”。不可能使用嵌套的 for 循环,因为我不知道编译时数组的数量。如果已知例如 4 个数组 (a,b,c,d),我可以使用 4 个循环:

for (int i = 0; i <= a.Length-1; i++)
{
   for (int j = 0; i <= b.Length-1; j++)
   {
      for (int k = 0; i <= c.Length-1; k++)
      {
         for (int m = 0; i <= d.Length-1; m++)
         {
            Response[f++] = a[i].toString()+","+b[j].toString()+","+c[k].toString()+","+d[m].toString();
         }
      }
   }
}

但是对于不同数量的数组,我不知道。

【问题讨论】:

  • 为什么不使用二维数组呢?并使用DFS方法生成组合
  • @Rawling - 这不是重复的。这个问题有可变数量的输入。另一个问题仅限于三个输入数组。
  • @Enigmativity 该问题的答案推广到此解决方案。
  • @Rawling - 对不起,我没有在那个答案中看到递归。我现在看到了。我的错。不过,我更喜欢我的回答。 :-)
  • @Enigmativity 这很公平,我认为你是对的,因为 question 不是重复的。

标签: c# arrays combinations


【解决方案1】:

这行得通:

Func<
    IEnumerable<IEnumerable<int>>,
    IEnumerable<IEnumerable<int>>> f0 = null;
f0 = xss =>
{
    if (!xss.Any())
    {
        return new [] { Enumerable.Empty<int>() };
    }
    else
    {
        var query =
            from x in xss.First()
            from y in f0(xss.Skip(1))
            select new [] { x }.Concat(y);
        return query;
    }
};

Func<IEnumerable<IEnumerable<int>>, IEnumerable<string>> f =
    xss => f0(xss).Select(xs => String.Join(",", xs));

所以如果我有这个输入:

var input = new []
{
    new [] { 1, 2, 3, 4, },
    new [] { 6, 7, 5, 2, 1, },
    new [] { 22, 4, 6, 8, 4, 8, 5, 4, },
};

我可以这样得到结果:

var results = f(input);


根据 cmets 中的请求,这是一个简单地汇总结果的版本:

Func<IEnumerable<IEnumerable<int>>, IEnumerable<int>> f = null;
f = xss =>
{
    if (!xss.Any())
    {
        return new [] { 0 };
    }
    else
    {
        var query =
            from x in xss.First()
            from y in f(xss.Skip(1))
            select x + y;
        return query;
    }
};

var input = new []
{
    new [] { 1, 2, 3, 4, },
    new [] { 6, 7, 5, 2, 1, },
    new [] { 22, 4, 6, 8, 4, 8, 5, 4, },
};

var results = f(input);

【讨论】:

  • 其实response不是字符串,我写的就是例子! response 是一个数学函数...您可以假设它像 response= a+b+c+d+.... 我可以为此目的使用此方法吗?!
  • 因为您只想对所有值求和?!请提供您正在寻找的输出的示例?!
  • 不!对于两个向量 a , b 如下: response=constant1*a+constant2*b+constant3*ab+constant4*a^2+constant5*b^2+constant6;对于三个向量 a、b、c 如下: response=constant1*a+constant2*b+constant3*c+constant4*ab+constant5*ac+constant6*bc+constant7*a^2+constant8*b^2+constant9*c^2+constant10;
  • @user3636337 - 我在我的答案中添加了一个求和版本。但似乎它甚至不像对值求和那么简单。我认为你需要澄清你的问题。
  • 谢谢,我的问题解决了……我按照自己的意愿改了,但是我没能实现它的算法!您是否也可以回答这个问题:stackoverflow.com/questions/24094602/
【解决方案2】:

我认为 linq 版本看起来很棒:

from i in a
from j in b
from k in c
from m in d
select String.Join(",", i, j, k, m)

但你的问题的答案并不容易。 Eric Lippert 在他的博客上写道:

http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx

【讨论】:

  • 其实response不是字符串,我写的就是例子! response 是一个数学函数...您可以假设它像 response= a+b+c+d.... 我可以为此目的使用此方法吗?!
  • 当然。 from 和 CartesianProduct 只返回一个 IEnumerable。只需更改 select 语句以选择您需要的内容。
【解决方案3】:

以下扩展方法模仿foreach循环的嵌套堆栈:

public static class Ext
{
    public static void ForEachNested<T>(
        this IEnumerable<IEnumerable<T>> sources,
        Action<IEnumerable<T>> action)
    {
        var enumerables = sources.ToArray();
        Stack<IEnumerator<T>> fe = new Stack<IEnumerator<T>>();
        fe.Push(enumerables[0].GetEnumerator());

        while (fe.Count > 0)
        {
            if (fe.Peek().MoveNext())
            {
                if (fe.Count == enumerables.Length)
                    action(new Stack<T>(fe.Select(e => e.Current)));
                else
                    fe.Push(enumerables[fe.Count].GetEnumerator());
            }
            else
            {
                fe.Pop().Dispose();
            }
        }
    }
}

你可以这样使用它:

new[] { a, b, c, d }.ForEachNested(e => { Response[f++] = string.Join(",", e); });

或者,做你的数学,

new[] { a, b, c, d }.ForEachNested(e => { Response[f++] = e.Sum(); });

这样做的好处是不需要执行数百个数组分配。

通常我会回避使用类似 LINQ 的方法来 act 而不是 query 但因为这是在密切模仿 foreach 循环的工作方式,所以我不这样做不要太在意。

【讨论】:

  • 我有一个问题,声明没有错误,但是当我使用它时,我定义了四个向量 a、b、c、d...并构造了一个由这些向量组成的数组,但是“ e" 函数 ForEachNested(...) 的参数无法识别
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-02
  • 2023-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多