Преобразование трехмерного массива в одномерный и обратно

Имеем трехмерный массив, в котором содержатся циферки или буковки. Не суть. Главное, мы знаем его размерность, например 3х3х3.

Всего 27 элементов.

В одной части проекта мы преобразуем этот массив в одномерный длиной 27 элементов и передаем эти элементы в другую часть проекта. *Так надо.*

Например:
/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .javascript.geshi_code {font-family:monospace;} .javascript.geshi_code .imp {font-weight: bold; color: red;} .javascript.geshi_code .kw1 {color: #000066; font-weight: bold;} .javascript.geshi_code .kw2 {color: #003366; font-weight: bold;} .javascript.geshi_code .kw3 {color: #000066;} .javascript.geshi_code .co1 {color: #006600; font-style: italic;} .javascript.geshi_code .co2 {color: #009966; font-style: italic;} .javascript.geshi_code .coMULTI {color: #006600; font-style: italic;} .javascript.geshi_code .es0 {color: #000099; font-weight: bold;} .javascript.geshi_code .br0 {color: #009900;} .javascript.geshi_code .sy0 {color: #339933;} .javascript.geshi_code .st0 {color: #3366CC;} .javascript.geshi_code .nu0 {color: #CC0000;} .javascript.geshi_code .me1 {color: #660066;} .javascript.geshi_code span.xtra { display:block; }

var a = [][][]; // это наш большой массив, определен заранее
var b = [];
for( i=0; i<3; i++) {
 for( j=0; j<3; j++) {
  for( k=0; k<3; k++) {
    b[] = a[i][j][k];
  }
 }
}
 


Совместно с этим передаем и размерность массива.

Теперь на другой стороне нам нужно, зная размерности и одномерный массив, собрать обратно данные в трехмерный массив.

То ли время позднее, то ли отпуск сказывается, но не придумывается. Можете подсказать? Желательно сразу программным кодом (на любом языке из типовых).

***

Наступило утро, посетили мысли. Думаю, как-то вот так:

/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .javascript.geshi_code {font-family:monospace;} .javascript.geshi_code .imp {font-weight: bold; color: red;} .javascript.geshi_code .kw1 {color: #000066; font-weight: bold;} .javascript.geshi_code .kw2 {color: #003366; font-weight: bold;} .javascript.geshi_code .kw3 {color: #000066;} .javascript.geshi_code .co1 {color: #006600; font-style: italic;} .javascript.geshi_code .co2 {color: #009966; font-style: italic;} .javascript.geshi_code .coMULTI {color: #006600; font-style: italic;} .javascript.geshi_code .es0 {color: #000099; font-weight: bold;} .javascript.geshi_code .br0 {color: #009900;} .javascript.geshi_code .sy0 {color: #339933;} .javascript.geshi_code .st0 {color: #3366CC;} .javascript.geshi_code .nu0 {color: #CC0000;} .javascript.geshi_code .me1 {color: #660066;} .javascript.geshi_code span.xtra { display:block; }

var a = [][][]; // это наш большой массив, еще пустой
var b = []; // А это заполненный одномерный массив с 9 элементами
var x = 0; // А это счетчик в одномерном массиве
for( i=0; i<3; i++) {
 for( j=0; j<3; j++) {
  for( k=0; k<3; k++) {
    a[i][j][k] = b[x];
    x++;
  }
 }
}
 


Кажется, должно работать.

1 ответов


Вышло что-то похожее на бред, но все же выставляю на всеобщей осмотр :)
Работать будет только для квадратных матриц :)



$arr = array();
for( $i=0; $i<3; $i++) {
  for( $j=0; $j<3; $j++) {
    for( $k=0; $k<3; $k++) {
      $arr[$i][$j][$k] = $i.$j.$k;
    }
  }
}


print_r($arr);

echo "<hr>";

$oneDimension = array();

for( $i=0; $i<3; $i++) {
  for( $j=0; $j<3; $j++) {
    for( $k=0; $k<3; $k++) {
      $oneDimension[] =$arr[$i][$j][$k];

    }
  }
}

$depth = 0;
$curr = 0;
$outArr = array();
$howMuch = pow(count($oneDimension),1/3);

for ($i=0; $i<$howMuch; $i++){
  $outArr[$i] = array();
  doArray($depth,$howMuch, $curr,$oneDimension, $outArr[$i]);
}


print_r($outArr);



function doArray(&$depth = 0, $howMuch, &$currentIndex,$oneDimension, &$outArray){
  $depth++;
  $arrayTemp = array();
  for ($i=0; $i<$howMuch; $i++){
    $arrayTemp[] = $oneDimension[$currentIndex];
    $currentIndex++;
  }
  $outArray[] = $arrayTemp;
  if ($depth < $howMuch ){
    doArray($depth, $howMuch, &$currentIndex,$oneDimension, &$outArray);
  }else{
    $depth = 0;
  }
}

 

Ага, вот и пригодился мой сериализатор/десериализатор :) Сериализует массив любой размерности и, что очень приятно, восстанавливает его обратно. Рабочий пример для матрицы размером 3х3х3.


        function Serialize(in_obj)
  {
    var elem_c = 0; // Для чисел, строк - длина строки, для массивов и объектов кол-во елементов
    var elem = ""; // Само значение
    var prefix = ""; // s - строка, n - число, o - объект

    switch (typeof(in_obj))
    {
      case "string":
        {
          prefix = "s";
          elem_c = in_obj.length;
          elem = in_obj;
          break;
        }
      case "object":
        {
          prefix = "o";
          var obj_str = "";
          for (var ind in in_obj)
          {
            var obj_t = typeof(in_obj[ind]);
            if (obj_t != "function")
            {
              var elem_str = Serialize(in_obj[ind]);
              obj_str = obj_str + ind.toString().length + ":" + ind + elem_str;
              elem_c++;
            }
          }
          elem = obj_str;
          break;
        }

      case "number":
        {
          prefix = "n";
          elem = in_obj.toString();
          elem_c = elem.length;
          break;
        }
    }

    var ret_str = prefix + ":" + elem_c + ":" + elem;

    return ret_str;
  }

  function Unserialize(in_str)
  {
    function p_unsrlz(in_str)
    {
      var pref = in_str.substring(0, 1);
      var stop_me = false;
      var cur_symb = "";
      var data_len = ""; // Длинна строки с данными или количество элементов массива (объекта)
      var read_len = 0; // Длинна прочитанной части
      var counter = 1; // Указатель текущего символа

      while (!stop_me)
      {
        counter++;
        cur_symb = in_str.substring(counter, parseInt(counter)+1);
        if (cur_symb != ":")
          data_len = data_len + cur_symb;
        else
          stop_me = true;
      }
      // counter указывает на двоеточие перед началом данных
      switch (pref)
      {
        case "n":
        case "s":
          {
            var data = new String;
            data = in_str.substring(parseInt(counter)+1, parseInt(counter) + 1 + parseInt(data_len));
            if (pref == "n")
              data = parseFloat(data);

            read_len = 3 + parseInt(data_len) + parseInt(data_len.length);

            break;
          }

        case "o":
          {
            var data = new Array(parseInt(data_len));
            read_len = 3 + data_len.length;
            for (var i = 0; i < parseInt(data_len); i++)
            {
              var my_key = p_unsrlz("s:" + in_str.substring(parseInt(counter)+1, in_str.length));
              counter = counter + parseInt(my_key.data_len) - 1;
              var my_obj_data = p_unsrlz(in_str.substring(parseInt(counter), in_str.length));
              data[my_key.data] = my_obj_data.data;
              counter = counter + parseInt(my_obj_data.data_len) - 1;
              read_len = read_len + (my_key.data_len - 2) + my_obj_data.data_len;
            }
            break;
          }
      }
      return {data: data, data_len: read_len};
    }

    var unsrlz = p_unsrlz(in_str);
    return unsrlz.data;
  }
 
Единственное условие - в массиве не должно быть циклических ссылок. Подробности - здесь.

Если надо, готов ответить на вопросы по самому алгоритму.

Для С++ что-то типа:


int l = 0;
T*** a = static_cast<T***>(new T[in]);
for(int i=0; i<in; i++) {
 a[i] = static_cast<T**>(new T[jn]);
 for(int j=0; j<jn; j++) {
  a[i][j] = new T[kn];
  for(int k=0; k<kn; k++, l++) {
    a[i][j][k] = b[l];
  }
 }
}
 
T - тип элементов, in, jn, kn - размерности, b - входящий одномерный массив, a - реузльтирующий 3-х мерный массив.