C#:使用任意尺寸设置数组中的所有值

时间:2010-09-27 15:10:57

标签: c# c#-4.0

我正在寻找一种方法将多维数组中的每个值设置为单个值。问题是在编译时维度的数量是未知的 - 它可以是一维的,也可以是四维的。由于foreach不允许您设置值,我可以通过哪种方式实现此目标?非常感谢。

5 个答案:

答案 0 :(得分:4)

虽然这个问题在表面看起来很简单,但它实际上比看起来更复杂。但是,通过认识到访问多维(甚至是锯齿状)数组中的每个位置都是笛卡儿关于数组索引集的产品操作 - 我们可以简化解决方案......并最终编写更优雅的解决方案。

我们将利用Eric Lippert's LINQ Cartesian Product实施来完成繁重的任务。如果您愿意,可以在他的博客上详细了解其工作原理。

虽然此实现特定于访问多维数组的单元格 - 但是应该相对容易地看到如何扩展它以访问锯齿状数组。

public static class EnumerableExt
{
    // Eric Lippert's Cartesian Product operator...
    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 }));
    }
}

class MDFill
{
    public static void Main()
    {
        // create an arbitrary multidimensional array
        Array mdArray = new int[2,3,4,5];

        // create a sequences of sequences representing all of the possible
        // index positions of each dimension within the MD-array
        var dimensionBounds = 
            Enumerable.Range(0, mdArray.Rank)
               .Select(x => Enumerable.Range(mdArray.GetLowerBound(x),
                      mdArray.GetUpperBound(x) - mdArray.GetLowerBound(x)+1));

        // use the cartesian product to visit every permutation of indexes
        // in the MD array and set each position to a specific value...
        int someValue = 100;
        foreach( var indexSet in dimensionBounds.CartesianProduct() )
        {
            mdArray.SetValue( someValue, indexSet.ToArray() );
        }
    }
}

将此代码分解为可重用的方法现在是微不足道的,该方法可用于锯齿状或多维数组......或任何可被视为矩形数组的数据结构。

答案 1 :(得分:1)

Array.Length会告诉你声明数组要存储的元素数量,因此可以按如下方式遍历数组(无论是矩形还是锯齿状):

for(var i=0; i<myMDArray.Length; i++)
   for(var j=0; j < myMDArray[i].Length; i++)
      DoSomethingTo(myMDArray[i][j]);

如果数组是矩形(所有子数组的长度相同),则可以获得第一个数组的长度并存储在变量中;它会略微提高性能。

当维度数量未知时,可以递归:

public void SetValueOn(Array theArray, Object theValue)
{
   if(theArray[0] is Array) //we haven't hit bottom yet
      for(int a=0;a<theArray.Length;a++)
         SetValueOn(theArray[a], theValue);
   else if(theValue.GetType().IsAssignableFrom(theArray[0].GetType()))
      for(int i=0;i<theArray.Length;i++)
         theArray[i] = theValue;
   else throw new ArgumentException(
         "theValue is not assignable to elements of theArray");
}

答案 2 :(得分:0)

我认为没有直接的方法可以做到这一点,所以你需要使用Rank属性来获取维数和SetValue方法(它采用带索引的数组)每个维度作为参数)。

一些代码片段可以帮助您入门(对于标准的多维数组):

bool IncrementLastIndex(Array ar, int[] indices) {
  // Return 'false' if indices[i] == ar.GetLength(i) for all 'i'
  // otherwise, find the last index such that it can be incremented,
  // increment it and set all larger indices to 0
  for(int dim = indices.Length - 1; dim >= 0; dim--) { 
    if (indices[dim] < ar.GetLength(dim)) {
      indices[dim]++;
      for(int i = dim + 1; i < indices.Length; i++) indices[i] = 0;
      return;
    }
  }
}

void ClearArray(Array ar, object val) {
  var indices = new int[ar.Rank];
  do {
    // Set the value in the array to specified value
    ar.SetValue(val, indices);
  } while(IncrementLastIndex(ar, indices));
}

答案 3 :(得分:0)

Array.Clear方法将让您清除(设置为默认值)多维数组中的所有元素(即int[,])。因此,如果您只想清除数组,可以编写Array.Clear(myArray, 0, myArray.Length);

似乎没有任何方法可以将数组的所有元素设置为任意值。

请注意,如果您将其用于锯齿状数组(即int[][]),则最终会得到一个对数组的空引用数组。也就是说,如果你写了:

int[][] myArray;
// do some stuff to initialize the array
// now clear the array
Array.Clear(myArray, 0, myArray.Length);

然后myArray[0]将为null

答案 4 :(得分:-1)

您是说要遍历每个元素和(如果可用)数组的每个维度并设置每个值吗?

如果是这种情况,你可以创建一个递归函数,迭代维度并设置值。检查MSDN上的Array.Rank属性和MSDN上的Array.GetUpperBound功能。

最后,我确信通用List<T>有某种方法可以做到这一点。