Как собрать массив из строчных данных

Рейтинг: 0Ответов: 2Опубликовано: 06.07.2023

Здравствуйте помогите пожалуйста понять алгоритм сборки данных в массив. надо собрать дерево категорий из строчных даных, все строки с ':' это данные которые должны быть в соответствующей категории. Пример данных

db1
catA
cat1a1
prod1:a0
prod2:a0
prod3:a0
cat2a2
prod1:a1
prod2:a1
prod3:a1
catB
cat1b1
prod1:b0
prod2:b0
prod3:b0
cat2b2
prod1:b1
prod2:b1
prod3:b1
db2
catC
cat1c1
prod1:c0
prod2:c0
prod3:c0
cat2c1
prod1:c1
prod2:c1
prod3:c1
catD
cat1d2
prod1:d0
prod2:d0
prod3:d0
cat2d2
prod1:d1
prod2:d1
prod3:d1

на выходе должен получится массив

$db = [
'db1' =>
  [
    'catA' => 
    [
      'cat1a1' => ['prod1:a0', 'prod2:a0', 'prod3:a0'] , 
      'cat2a2' => ['prod1:a1', 'prod2:a1', 'prod3:a1'] 
    ],
    'catB' => 
    [
      'cat1b1' => ['prod1:b0', 'prod2:b0', 'prod3:b0'],
      'cat2b2' => ['prod1:b1', 'prod2:b1', 'prod3:b1']
    ]
  ], 
'db2' => 
   [
     'catC' => 
     [
       'cat1c1' => ['prod1:c0', 'prod2:c0', 'prod3:c0'] , 
       'cat2c2' => ['prod1:c1', 'prod2:c1', 'prod3:c1'] 
     ],
     'catD' => 
     [
       'cat1d1' => ['prod1:d0', 'prod2:d0', 'prod3:d0'],
       'cat2d2' => ['prod1:d1', 'prod2:d1', 'prod3:d1']
     ]
   ]
];

дело в том что структура данных собирается по строчно, попробую объяснить: первая строка без ':' это главная категория если следующая строка тоже без знака ':' то это под категория и так далее до первой строки со знаком ':' типо db1->catA->cat1a1 если в строке есть знак ':' то данные записываются в последую под категорию.

плюс еще db1,catA,cat1a это пример, на сомом деле все данные разные я не могу ни к чему привязаться кроме знаков "\n" и ":"

db1->catA->cat1a=prod1:a0
db1->catA->cat1a=prod2:a0
db1->catA->cat1a=prod3

Ответы

▲ 1

phew

не пытайтесь даже понять это, но оно работает.

какая задача, такое и решение)

$data = [
    "db1",
    "catA",
    "cat1a1",
    "prod1:a0",
    "prod2:a0",
    "prod3:a0",
    "cat2a2",
    "prod1:a1",
    "prod2:a1",
    "prod3:a1",
    "catB",
    "cat1b1",
    "prod1:b0",
    "prod2:b0",
    "prod3:b0",
    "cat2b2",
    "prod1:b1",
    "prod2:b1",
    "prod3:b1",
    "db2",
    "catC",
    "cat1c1",
    "prod1:c0",
    "prod2:c0",
    "prod3:c0",
    "cat2c1",
    "prod1:c1",
    "prod2:c1",
    "prod3:c1",
    "catD",
    "cat1d2",
    "prod1:d0",
    "prod2:d0",
    "prod3:d0",
    "cat2d2",
    "prod1:d1",
    "prod2:d1",
    "prod3:d1"
];

function parse($data, &$from, $depth) {
    if ($depth > 3) {
        return false;
    }
    
    $tmpArr = [];
    $foundData = false;
    for ($i = $from; $i < count($data); $i++) {
        $row = $data[$i];

        if (strripos($row, ":") === false) {
            if ($foundData) {
                $from = $i;
                return $tmpArr;
            }

            $from = $i+1;
            $res = parse($data, $from, $depth+1);
            if ($res == false) {
                $from--;
                if (!count($tmpArr)) {
                    return false;
                } else {
                    return $tmpArr;
                }
            }
            $tmpArr[$row] = $res;
            $i = $from-1;
            continue;
        }

        $foundData = true;
        $tmpArr[] = $row;
    }

    $from = $i;
    
    return $tmpArr;
}

$from = 0;
$result = parse($data, $from, 0);

print_r($result);

результат:

Array
(
  [db1] => Array  (

      [catA] => Array  (

          [cat1a1] => Array  (

              [0] => prod1:a0
              [1] => prod2:a0
              [2] => prod3:a0
          )

          [cat2a2] => Array  (

              [0] => prod1:a1
              [1] => prod2:a1
              [2] => prod3:a1
            )

        )

      [catB] => Array  (

          [cat1b1] => Array  (

              [0] => prod1:b0
              [1] => prod2:b0
              [2] => prod3:b0
          )

          [cat2b2] => Array  (

              [0] => prod1:b1
              [1] => prod2:b1
              [2] => prod3:b1
            )

        )

    )

  [db2] => Array  (

      [catC] => Array  (

          [cat1c1] => Array  (

              [0] => prod1:c0
              [1] => prod2:c0
              [2] => prod3:c0
          )

          [cat2c1] => Array  (

              [0] => prod1:c1
              [1] => prod2:c1
              [2] => prod3:c1
            )

        )

      [catD] => Array  (

          [cat1d2] => Array  (

              [0] => prod1:d0
              [1] => prod2:d0
              [2] => prod3:d0
          )

          [cat2d2] => Array  (

              [0] => prod1:d1
              [1] => prod2:d1
              [2] => prod3:d1
            )

        )

    )

)
▲ 0
$data=<<<HEREDOC
db1
catA
cat1a1
prod1:a0
prod2:a0
prod3:a0
cat2a2
prod1:a1
prod2:a1
prod3:a1
HEREDOC;

$res=array();

$data=explode($data,PHP_EOL); //подготовка для цикла
for($i=0;$i<lenght($data);$i++){ //о есть если проходим циклом по каждой строке/ for а не foreach так как будем юзать i как индекс следующих элементов
//проверяем, является ли текущая стока записью уровня\класса\важности db те первичного ключа
if ($data[$i] dont_contain ':'){ //т если в текущей строке нет двоеточия
    if($data[$i+2] dont_contain ':') { //если двоеточия нет и в следующей строке
        if($data[$i+3] dont_contain ':') {// если нет и в третьей строке значит запись относится к dbN
        //здесь два варианта,- записывать всё в строку и потом произвести eval либо работать с результативным массивом
        $db=$data[$i] //помещаем в переменную название первого ключа, то есть как бы создаём конструктор\\не в смысле класса
        continue(); //дабы не раздвоиться
        }}}

//проверяем является ли текущая строка записью класса catN, то есть вторичного ключа
if ($data[$i] dont_contain ':'){ //т если в текущей строке нет двоеточия
    if($data[$i+2] dont_contain ':') { //если двоеточия нет и в следующей строке
            $cat1=$data[$i];//так же сохраняем строку в переменную для доступа по типу $data[$db][$cat1]....
            continue;
        }}}

//то же условие для записи уровня cat2

if ($data[$i+1] dont_contain ':'){ //то есть является ли строка заголовком последнего уровня
    $cat2=$data[$i];
    cintinue; //дабы не юзать елсе тк ухудшится читабельность и редактируемость
    }

//если не один из континуев не сработал, значит в записи есть двоеточие, следовательно это простой член массива, а не заголовок
$res[$db][$cat1][$cat2] append $data[$i] 

}

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

суть в том, что ключ первого уровня результативного массива, находится в той строке, после которой следует две строки не содержащих двоеточия, то же для второго ключа и третьего. заменить оператор dont_contain на проверку эквивалентную "не содержит", заменить append, на добавление к нумерованому массиву, а не присвоению. upd: нужна также проверка чтобы $i+N не выходила за пределы массива.