如何循环遍历多维数组?

27
foreach (String s in arrayOfMessages)
{
    System.Console.WriteLine(s);
}

作为参数传递了string[,] arrayOfMessages

我想确定哪些字符串来自于arrayOfMessages[0,i]arrayOfMessages[n,i],其中n是该数组的最后一个索引。


1
为什么不直接使用带索引的循环呢? - Jesus Ramos
7个回答

56

只需使用两个嵌套的for循环。为了获取维度的大小,您可以使用GetLength()

for (int i = 0; i < arrayOfMessages.GetLength(0); i++)
{
    for (int j = 0; j < arrayOfMessages.GetLength(1); j++)
    {
        string s = arrayOfMessages[i, j];
        Console.WriteLine(s);
    }
}

这假定您实际拥有string[,] 。在.NET中,也可以有从0开始索引的多维数组。在这种情况下,它们必须在C#中表示为Array,您需要使用GetLowerBound()GetUpperBound()获取每个维度的边界。


11

使用嵌套的for循环:

for (int row = 0; row < arrayOfMessages.GetLength(0); row++)
{
   for (int col = 0; col < arrayOfMessages.GetLength(1); col++)
   {
      string message = arrayOfMessages[row,col];
      // use the message
   }    
}

7

不要使用 foreach - 使用嵌套的 for 循环,每一维使用一个循环。

你可以使用 GetLength 方法获取每个维度中的元素数量。

参见MSDN上的多维数组 (C#编程指南)


3

看起来你找到了一个适合你问题的答案,但由于标题要求多维数组(我理解为2个或更多),而这是我在搜索时得到的第一个搜索结果,所以我将添加我的解决方案:

public static class MultidimensionalArrayExtensions
{
    /// <summary>
    /// Projects each element of a sequence into a new form by incorporating the element's index.
    /// </summary>
    /// <typeparam name="T">The type of the elements of the array.</typeparam>
    /// <param name="array">A sequence of values to invoke the action on.</param>
    /// <param name="action">An action to apply to each source element; the second parameter of the function represents the index of the source element.</param>
    public static void ForEach<T>(this Array array, Action<T, int[]> action)
    {
        var dimensionSizes = Enumerable.Range(0, array.Rank).Select(i => array.GetLength(i)).ToArray();
        ArrayForEach(dimensionSizes, action, new int[] { }, array);
    }
    private static void ArrayForEach<T>(int[] dimensionSizes, Action<T, int[]> action, int[] externalCoordinates, Array masterArray)
    {
        if (dimensionSizes.Length == 1)
            for (int i = 0; i < dimensionSizes[0]; i++)
            {
                var globalCoordinates = externalCoordinates.Concat(new[] { i }).ToArray();
                var value = (T)masterArray.GetValue(globalCoordinates);
                action(value, globalCoordinates);
            }
        else
            for (int i = 0; i < dimensionSizes[0]; i++)
                ArrayForEach(dimensionSizes.Skip(1).ToArray(), action, externalCoordinates.Concat(new[] { i }).ToArray(), masterArray);
    }

    public static void PopulateArray<T>(this Array array, Func<int[], T> calculateElement)
    {
        array.ForEach<T>((element, indexArray) => array.SetValue(calculateElement(indexArray), indexArray));
    }
}

使用示例:

var foo = new string[,] { { "a", "b" }, { "c", "d" } };
foo.ForEach<string>((value, coords) => Console.WriteLine("(" + String.Join(", ", coords) + $")={value}"));
// outputs:
// (0, 0)=a
// (0, 1)=b
// (1, 0)=c
// (1, 1)=d

// Gives a 10d array where each element equals the sum of its coordinates:
var bar = new int[4, 4, 4, 5, 6, 5, 4, 4, 4, 5];
bar.PopulateArray(coords => coords.Sum());

一般的想法是通过维度递归下去。我确信这些函数不会赢得效率奖,但它可以作为我的格子结构的一次性初始化程序,并带有一个足够好的ForEach函数,以公开值和索引。主要的缺点是我没有解决如何自动识别数组中的T类型,因此在涉及类型安全时需要小心。


2

更为功能化的方法是使用LINQ,我总觉得它比循环更好。它使代码更易于维护和阅读。下面的代码片段展示了使用方法或流畅的LINQ语法之一的解决方案。

string[,] arrayOfMessages = new string[3, 2] { { "Col1","I am message 1" }, { "Col2", "I am message 2" }, { "Col3", "I am message 3" } };
var result = arrayOfMessages.Cast<string>()
                            .Where((msg, index) => index % 2 > 0);

foreach (var msg in result)
{
    Console.WriteLine(msg);
}

LINQ扩展方法不适用于多维数组,因为它们没有实现 IEnumerable<T> 接口。这就是 Cast<T> 起作用的地方。它基本上将整个数组转换为 IEnumerable<T>。在我们的情况下,它会将多维数组展平成类似于 IEnumerable<string> 的东西:

{ "Col1", "I am message 1", "Col2", "I am message 2", "Col3", "I am message 3" }

你还可以使用 OfType<T> 而不是 Cast<T>。它们之间唯一的区别在于,对于混合数据类型的集合,OfType<T> 会忽略无法转换的值,而 Cast<T> 则会引发 InValidCastException 异常。
接下来,我们只需要应用一个 LINQ 操作符,该操作符会忽略(或过滤掉)偶数索引处的值。因此,我们使用 Where 操作符的一个重载版本,其 Func 委托的类型为 Func<TSource, int, bool>,其中 TSource 是集合中的每个项目,int 是项目在集合中的索引,bool 是返回类型。
在上面的代码片段中,我使用了一个 lambda 表达式,该表达式计算每个项目的索引,并仅当索引为奇数时才返回 true。

1

类似这样的代码可以正常工作:

int length0 = arrayOfMessages.GetUpperBound(0) + 1;
int length1 = arrayOfMessages.GetUpperBound(1) + 1;

for(int i=0; i<length1; i++) { string msg = arrayOfMessages[0, i]; ... }
for(int i=0; i<length1; i++) { string msg = arrayOfMessages[length0-1, i]; ... }

0
您可以使用以下代码来运行多维数组。
foreach (String s in arrayOfMessages)
{
    System.Console.WriteLine("{0}",s);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接