3

我需要 6 个数组的笛卡尔积 - 问题是任何时候最多 5 个数组可能为空。当所有数组都被填充时它工作得很好,但是当任何数组为空时炸弹

我的数组是这样的

MatrixArray_1[0] = 1
MatrixArray_1[1] = 2

MatrixArray_2[0] = null
MatrixArray_2[1] = null

MatrixArray_n[0] = 2
MatrixArray_n[1] = 2

等等

我目前正在使用此代码...源自 http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx

var product1 =  from first in MatrixArray_1
                from second in MatrixArray_2
                from third in MatrixArray_3
                from fourth in MatrixArray_4
                from fifth in MatrixArray_5
                from sixth in MatrixArray_6
                select new[] { first, second, third, fourth, fifth, sixth };
            string[][] myCombos_linq = product1.ToArray();

我试过 putMatrixArray_n where first != null但是它停在第一个空数组并且没有通过所有剩余的数组读取,所以我的返回数组总是 0 行,即使 array1 和数组 3 被填充。

代码/逻辑的任何更改在此时都值得赞赏!TIA

4

3 回答 3

3

由于 Eric 的方法是使用IEnumerable<IEnumerable<T>>,因此您必须执行以下操作:

埃里克的代码:

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 sequences = new int?[][] { MatrixArray_1, MatrixArray_2, ..., MatrixArray_6 };
var cartesianSequence = sequences.CartesianProduct();

更改呼叫站点:

var cartesianSequence = sequences.Where(a => a.Any(e => e != null)).CartesianProduct();

Where 调用将排除所有元素为空的序列。

要排除空数组以及仅包含空值的数组:

var cartesianSequence = sequences.Where(a => a != null && a.Any(e => e != null)).CartesianProduct();

或者,使用查询理解:

var filteredSequences = 
    from sequence in sequences
    where sequence != null && sequence.Any(e => e != null)
    select sequence
var cartesianSequence = filteredSequences.CartesianProduct();

编辑

另一种可能性是您想要排除每个序列的空元素,即使某些元素是非空的:

var filteredSequences = 
    from sequence in sequences
    where sequence != null && sequence.Any(e => e != null)
    select (from v in sequence where v.HasValue select s)
var cartesianSequence = filteredSequences.CartesianProduct();

或者

var cartesianSequence = sequences
    .Where(s => s != null && s.Any(e => e != null))
    .Select(s => s.Where(v => v != null))
    .CartesianProduct();

但很难确切知道该建议什么,因为我们不知道您对结果做了什么。

于 2012-02-14T17:23:28.733 回答
1

我是否正确理解您想要排除任何first,second等(如果是)null?这很容易:

只需添加

select new [] { first, second, third, fourth, fifth, sixth }.Where(x => x != null)

到您的查询。

first或者,如果,second等中的任何一个是,您是否要排除整个六元组null?这也很容易。只需添加

where new [] { first, second, third, fourth, fifth, sixth }.All(x => x != null)

到您的查询。您甚至可以使用let这样您就不会创建两次数组。

于 2012-02-14T17:26:16.673 回答
0

根据定义(我引用前面提到的 Eric Lippert博客)。“两个序列 S1 和 S2 的笛卡尔积是所有可能的双元素序列的序列,其中第一个元素来自 S1,第二个元素来自 S2。”

如果您概括定义,它将是:

任何 n 个序列 S1、S2、...Sn 的笛卡尔积是所有可能的 n 元素序列的序列,其中第一个元素来自 S1,第二个元素来自 S2,N 个元素来自 Sn

请注意,第一个元素应始终来自第一个元素。

如果您要过滤掉第一个数组的空值,这意味着整个输入将丢失,过滤掉的输入看起来像这样:

(空,x2,...xn)

这是一个完整的例子:

array1 = {null, 1, 2}
array2 = {A}

array1 & array2 的笛卡尔积 = {{null, A}, {1, A}, {2, A} }

现在,让我们在 First != null 的地方应用过滤器。

array1 & array2 的笛卡尔积 = {{1, A}, {2, A}}

假设我们将 array1 的值更改为:

array1 现在 = {null,null}

array1 和 array2 的笛卡尔积,过滤器 = {}

结果是空集。为了获得笛卡尔积,您必须从每个数组中获得一个输入。您的问题可以调整以解决这一事实。

于 2012-02-14T17:48:21.990 回答