我需要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();
我尝试过放置MatrixArray_n where first != null
,但它在第一个null数组处停止,并且不会读取所有剩余的数组,因此即使填充了array1和array3,我的返回数组也始终是0行。
代码/逻辑的更改在此时此刻,任何事情都值得赞赏!TIA
由于Eric的方法是使用IEnumerable<IEnumerable<T>>
,您必须执行以下操作:
Eric的代码:
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调用将排除所有元素都为null的序列。
要排除空数组以及仅包含空值的数组:
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();
但很难确切知道该建议什么,因为我们不知道你对结果做了什么。
如果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
,这样就不会创建两次数组。
根据定义(我引用了前面提到的Eric Lippert博客)。"两个序列S1和S2的笛卡尔乘积是所有可能的两个元素序列的序列,其中第一个元素来自S1,第二个元素来自S2;
如果你将定义概括为:
任意n个序列S1,S2,…的笛卡尔乘积,。。。Sn是所有可能的n元素序列的序列,其中第一个元素来自S1,第二个元素来自S2,n元素来自Sn
请注意,第一个元素应始终来自第一个元素。
如果您要过滤掉第一个数组的空值,这意味着整个entery将丢失,那么过滤掉的entery如下所示:
(空,x2,…xn)
下面是一个完整的例子:
array1={null,1,2}
array2={A}array1&array2={{null,A},{1,A}}
现在,让我们在First!=无效的
array1&array2={{1,A},{2,A}}}
假设我们将array1的值更改为:
array1现在={null,null}
array1&array2与过滤器={}
结果为空集。为了得到笛卡尔乘积,你必须从每个数组中得到一个entery。你的问题可以根据这个事实进行调整。