@artgor261

Как склеить несколько подмассивов расположенных в одном массиве типа Object?

Задача такова: есть функция которая на вход принимает массив типа Object с неограниченным количеством элементов. Элементами массива должны быть массивы любых типов. Мне нужно склеить эти самые массивы в один, но при условии что у переданных массивов совпадают типы данных, в противном случае нужно вывести null. Я уже реализовал проверку на совпадение типов данных массивов, довольно коряво, но это не важно, вопрос в другом: я не могу склеить переданные массивы в один. Вот мой код:

static Array Combine(params Object[] array)
{
      List<Type> types = Type.GetTypeArray(array).OrderBy(x => x.Name).ToList(); //отсортированный список типов данных элементов
      List<Type> typesWithoutDublicates = new List<Type>(); //список тех же типов но без дубликатов

      for (int i = 0; i < types.Count - 1; i++)
            if (types[i] != types[i + 1])
                 typesWithoutDublicates.Add(types[i]); 

      if (typesWithoutDublicates.Count > 0) //если элементов больше нуля значит типы не совпадают
          return null;
      
      //требуется помощь в этом участке кода:
      Array resultArray = Array.CreateInstance(array.GetType().GetElementType(), array.Length); //создание массива
      Array.Copy(array, resultArray, array.Length);
      return resultArray;
}


Входные данные:

public static void Main()
{
     var ints = new[] { 1, 2 };
     var strings = new[] { "A", "B" };

     Print(Combine(ints, ints, ints));
     Print(Combine(ints));
     Print(Combine());
     Print(Combine(strings, strings));
     Print(Combine(ints, strings));
     Print(Combine(ints, ints));
}


Метод Print:

static void Print(Array array)
{
     if (array == null)
     {
          Console.WriteLine("null");
          return;
     }
     for (int i = 0; i < array.Length; i++)
           Console.Write("{0} ", array.GetValue(i));
     Console.WriteLine();
}
  • Вопрос задан
  • 97 просмотров
Решения вопроса 2
sarapinit
@sarapinit Куратор тега C#
Точу водой камень
DEL (первое решение было неверным)

UPD:

private static Array Combine(params object[] arrays)
        {
            if (arrays.Length == 0) return null;
            if (arrays.Length == 1) return (Array)arrays[0];

            var totalLength = ((Array)arrays[0]).Length;
            var elemType = arrays[0].GetType().GetElementType();
            for (int i = 1; i < arrays.Length; i++)
            {
                var nextElemType = arrays[i].GetType().GetElementType();
                if (nextElemType != elemType) return null;
                totalLength += ((Array)arrays[i]).Length;
            }
            
            Array resultArray = Array.CreateInstance(elemType, totalLength);

            var offset = 0;
            foreach (Array array in arrays)
            {
                Array.Copy(array, 0, resultArray, offset, array.Length);
                offset += array.Length;
            }

            return resultArray;
        }
Ответ написан
FoggyFinder
@FoggyFinder
1. Вы не учитываете вложенность массивов: размер нового массива должен быть равен сумме длин всех входящих массивов. За первый пробег вы узнаете общий размер и проверяете что все типы совпадают, за второй пробег уже копируете.
Тогда получится нечто вроде такого

static Array Combine(params object[] arr)
{
    if (arr.Length == 0)
    {
        return null;
    }

    var totalSize = 0;
    Type type = null;
    foreach (Array inner in arr)
    {
        var innerType = inner.GetType();
        type ??= innerType;

        if (innerType != type)
        {
            return null;
        }

        totalSize += inner.Length;
    }

    var resultArr = Array.CreateInstance(type.GetElementType(), totalSize);
    var currentSize = 0;

    foreach (Array inner in arr)
    {
        Array.Copy(inner, 0, resultArr, currentSize, inner.Length);
        currentSize += inner.Length;
    }

    return resultArr;
}


2. Отказаться от возвращения Array и перейти к дженерикам. Тогда можно использовать Linq в виде связки SelectMany + ToArray(), в SelectMany нужно будет привести к нужному типу.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы