C#: преобразовать вложенный список в nd-массив - PullRequest
2 голосов
/ 16 июня 2020

Я хочу преобразовать вложенный список с произвольным количеством уровней вложенности типа T в многомерный массив типа T

Это в точности похоже на this , но с произвольным количеством уровней, что подразумевает рекурсию.

Как это можно сделать с C#?

Мой тип, например,

List<List<List<List<int>>>>

и ожидал либо int[][][][], либо int[,,,], предпочтительно последний.

  • Это, конечно, при условии, что каждый список братьев и сестер имеет одинаковый размер.

1 Ответ

1 голос
/ 16 июня 2020

Вот решение для n измерений. Я создаю фальшивый список из 4 измерений для вашего примера с помощью MakeList (). Ключ должен сначала найти размеры и их размер, что делается в CountDimensions. Этот массив измерений позволяет вам создать массив нужного размера с помощью Array.CreateInstance. Затем I l oop по всем значениям, создавая массив индексов, который увеличивается 1 на 1 и распространяется на следующие измерения, когда одно из них заполнено. Тот же массив индексов используется для просмотра списков с помощью рекурсии с помощью GetListValue.

Вероятно, это не оптимально для производительности, но должно дать вам начало.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace NestedList
{
    public class ListToArray
    {
        public Array Convert(IList input)
        {
            var dimensions = CountDimensions(input).ToArray();
            var result = Array.CreateInstance(typeof(int), dimensions);

            var indexes = new int[dimensions.Length];
            while (indexes[0] < dimensions[0]) 
            {
                var currentValue = GetListValue(input, indexes, 0);
                result.SetValue(currentValue, indexes);

                // Inc last index, propagate to higher if needed
                IncrementIndex(indexes, dimensions);
            }

            return result;
        }

        private int GetListValue(IList input, int[] indexes, int depth)
        {
            if (input[indexes[depth]] is IList sublist)
            {
                return GetListValue(sublist, indexes, depth + 1);
            }
            return (int)input[indexes[depth]];
        }

        private void IncrementIndex(int[] indexes, int[] dimensions)
        {
            var iIndex = indexes.Length - 1;
            indexes[iIndex] = indexes[iIndex] + 1;
            while (iIndex > 0 && indexes[iIndex] > dimensions[iIndex]-1)
            {
                indexes[iIndex] = 0;
                iIndex--;
                indexes[iIndex] = indexes[iIndex] + 1;
            }
        }

        private IEnumerable<int> CountDimensions(IList input)
        {
            yield return input.Count;
            if (input.Count > 0 && input[0] is IList sublist)
            {
                foreach (var value in CountDimensions(sublist))
                {
                    yield return value;
                }
            }
            yield break;
        }

    }

    public class Program
    {
        static void Main()
        {
            var dec = new ListToArray();
            var array = dec.Convert(MakeList());
        }

        private static List<List<List<List<int>>>> MakeList()
        {
            const int dim1 = 3;
            const int dim2 = 4;
            const int dim3 = 2;
            const int dim4 = 5;

            var nextValue = 0;
            var dim1List = new List<List<List<List<int>>>>();
            for (var x1 = 0; x1 < dim1; ++x1)
            {
                var dim2List = new List<List<List<int>>>();
                for (var x2 = 0; x2 < dim2; ++x2)
                {
                    var dim3List = new List<List<int>>();
                    for (var x3 = 0; x3 < dim3; ++x3)
                    {
                        var dim4List = new List<int>();
                        for (var x4 = 0; x4 < dim4; ++x4)
                        {
                            var element4 = nextValue++;
                            dim4List.Add(element4);
                        }
                        dim3List.Add(dim4List);
                    }
                    dim2List.Add(dim3List);
                }
                dim1List.Add(dim2List);
            }

            return dim1List;
        }
    }
}

Изменить: I изначально оставил переменную для другого решения, теперь удален.

...