How do you loop through a multidimensional array?

后端 未结 7 1359
陌清茗
陌清茗 2021-01-03 19:50
foreach (String s in arrayOfMessages)
{
    System.Console.WriteLine(s);
}

string[,] arrayOfMessages is being passed in as a parameter

相关标签:
7条回答
  • 2021-01-03 20:19

    It looks like you found an answer suitable for your problem, but since the title asks for a multidimensional array (which I read as 2 or more), and this is the first search result I got when searching for that, I'll add my solution:

    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));
        }
    }
    

    Usage example:

    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());
    

    General idea is to recurse down through dimensions. I'm sure the functions won't win efficiency awards, but it works as a one-off initialiser for my lattice and comes with a nice-enough ForEach that exposes the values and indices. Main downside I haven't solved is getting it to automatically recognise T from the Array, so some caution is required when it comes to the type safety.

    0 讨论(0)
  • 2021-01-03 20:22

    With a nested for loop:

    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
       }    
    }
    
    0 讨论(0)
  • 2021-01-03 20:23

    Simply use two nested for loops. To get the sizes of the dimensions, you can use 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);
        }
    }
    

    This assumes you actually have string[,]. In .Net it's also possible to have multidimensional arrays that aren't indexed from 0. In that case, they have to be represented as Array in C# and you would need to use GetLowerBound() and GetUpperBound() the get the bounds for each dimension.

    0 讨论(0)
  • 2021-01-03 20:25

    Something like this would work:

    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 讨论(0)
  • 2021-01-03 20:29

    Don't use foreach - use nested for loops, one for each dimension of the array.

    You can get the number of elements in each dimension with the GetLength method.

    See Multidimensional Arrays (C# Programming Guide) on MSDN.

    0 讨论(0)
  • 2021-01-03 20:29

    A more functional approach would be to use LINQ, which I always find better than loops. It makes the code more maintainable and readable. The below given code snippet shows one of the solution using Method or Fluent LINQ syntax.

    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 extension methods are not available to multi-dimensional arrays since they do not implement IEnumerable<T> interface. That's where Cast<T> comes into picture. It basically casts the whole array into IEnumerable<T>. In our case it will flatten out the multi-dimensional array into IEnumerable<string> something like:

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

    You can also use OfType<T> instead of Cast<T>. The only difference between them is that in case of collections with mixed data types, while OfType<T> ignores values which it is unable to cast, Cast<T> will throw an InValidCastException.

    Next, all we need to do is to apply a LINQ operator that ignores (or filters out) values at even indices. So we use an overload of Where operator whose Func delegate is of the type Func<TSource, int, bool>, where TSource is each item in the collection, int is the index of the item in the collection and bool is the return type.

    In the above snippet, I used a lambda expression which evaluates each item index and returns true only when it is an odd number.

    0 讨论(0)
提交回复
热议问题