想象有一个包含2列的多维数组,每列具有完全相同的元素数:
int[,] virtualArray = new int[800,2];
如果我要在一个循环中遍历此类数组 -然后我将执行以下操作:
int columnCount = 2;
int eachColumnElementCount = 800;
int totalCombinationCount = Convert.ToInt32(Math.Pow(eachColumnElementCount, columnCount)); // 640_000
for(int i = 0; i < totalCombinationCount ; i++) {
int columnOneIndex= index / totalCombinationCount ;
int columnTwoIndex= index - totalCombinationCount * eachColumnElementCount;
}
结果将是:
0,0(i = 0)
0,1
..
0,799(i = 799)
1,0(i = 800)
1,1
..
1,799
..
799,799(i = 640_000-1)
现在,我想扩展当前的实现,以在具有3列的多维数组上的一维循环中进行迭代!即给定的预期结果是,在每一列中我们具有相同的800个元素计数,应为:
int[,] virtualArray = new int[800,3];
int columnCount = 3;
int eachColumnElementCount = 800;
int totalCombinationCount = Convert.ToInt32(Math.Pow(eachColumnElementCount, columnCount)); // 512_000_000
for(int i = 0; i < totalCombinationCount ; i++) {
// int index1 = 0; // ??
// int index2 = 0; // ??
// int index3 = 0; // ??
}
0,0,0(i = 0)
0,0,1
...
0,0,799
...
10,80,156
...
799,799,799(i = 512_000_000-1)
对于3列的情况,我无法给出公式。是否可以在单个循环中循环遍历此类数组?
答案 0 :(得分:3)
当然可以,请尝试以下Java代码:
int columnCount = 3;
int eachColumnElementCount = 800;
int totalCombinationCount = (int)Math.pow(eachColumnElementCount, columnCount); // 800*800*800
for(int i = 0; i < totalCombinationCount ; i++) {
int column1Index= i % eachColumnElementCount;
int column2Index= i / eachColumnElementCount % eachColumnElementCount ;
int column3Index= i / eachColumnElementCount / eachColumnElementCount ;
System.out.println(column3Index+","+column2Index+","+column1Index);
}
答案 1 :(得分:1)
我知道您问过如何对三列进行此操作,但是如果您想将其概括化以用于N列,则会有些麻烦。
您要计算的是Cartesian Product。
埃里克·利珀特posted a Linq solution to this in his blog。
它看起来像这样:
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}));
}
(请阅读我在上面链接的Eric Lippert的博客文章,以了解有关其工作原理的详细信息。)
为了对二维数组使用此方法,我们需要一种按列而不是按行迭代数组内容的方法:
public static IEnumerable<T> Column<T>(T[,] array, int column)
{
for (int row = array.GetLowerBound(0); row <= array.GetUpperBound(0); ++row)
yield return array[row, column];
}
public static IEnumerable<IEnumerable<T>> ByColumn<T>(T[,] array)
{
for (int column = array.GetLowerBound(1); column <= array.GetUpperBound(1); ++column)
yield return Column(array, column);
}
然后我们可以像这样解决5x4数组:
char[,] array =
{
{ 'A', 'F', 'K', 'P' },
{ 'B', 'G', 'L', 'Q' },
{ 'C', 'H', 'M', 'R' },
{ 'D', 'I', 'N', 'S' },
{ 'E', 'J', 'O', 'T' },
};
foreach (var combination in CartesianProduct(ByColumn(array)))
Console.WriteLine(string.Concat(combination));
请注意,您不需要为不同的列数编写不同的代码-这适用于大于一的任何列数。
在一个简单的控制台应用程序中将整个内容放在一起:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
static class Program
{
static void Main()
{
char[,] array =
{
{ 'A', 'F', 'K', 'P' },
{ 'B', 'G', 'L', 'Q' },
{ 'C', 'H', 'M', 'R' },
{ 'D', 'I', 'N', 'S' },
{ 'E', 'J', 'O', 'T' },
};
foreach (var combination in CartesianProduct(ByColumn(array)))
Console.WriteLine(string.Concat(combination));
}
public static IEnumerable<T> Column<T>(T[,] array, int column)
{
for (int row = array.GetLowerBound(0); row <= array.GetUpperBound(0); ++row)
yield return array[row, column];
}
public static IEnumerable<IEnumerable<T>> ByColumn<T>(T[,] array)
{
for (int column = array.GetLowerBound(1); column <= array.GetUpperBound(1); ++column)
yield return Column(array, column);
}
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}));
}
}
}