Как фильтровать массивы и объекты по пути, сохраняя структуру нетронутой - PullRequest
0 голосов
/ 20 декабря 2018

Я разрабатываю JSON API, который работает на PHP 7.2.Одной из функций API является простой фильтр «только покажи мне эти столбцы».Я хотел бы иметь возможность сделать эту динамику без необходимости вручную обрабатывать каждый «уровень» в пути.

Мой первый подход состоял в том, чтобы поддерживать только вложенный путь глубиной в пять уровней.Это покрывает большинство случаев использования, и это хорошо работало в течение нескольких лет.

/ api / request / stuff? Column = col1-sub1-data2, col1-sub2

Полная структура (можетбыть объектом или массивом, но я могу привести к массиву при необходимости):

[
  'col1' => [
    'sub1' => [
      'data1' => false,
      'data2' => 'abc',
      'data3' => 123
    ],
    'sub2' => [
      'other1' => true,
      'data3' => 987
    ]
  ],
  'col2' => [
  ]
]

Вот пример моего очень наивного подхода:

foreach ($columns as $column) {
    $path = explode('-', $column);

    if (!is_array($path) || empty($path)) {
        continue;
    }

    $pathCount = count($path);

    switch ($pathCount) {
        case 0:
        case 1:
            /* Too shallow. These should be handled before this point anyway... */
            continue 2;
        case 2:
            if (!isset($detailObject[ $path[ 0 ] ][ $path[ 1 ] ])
            ) {
                continue 2;
            }

            $newArray[ $path[ 0 ] ][ $path[ 1 ] ] = $detailObject[ $path[ 0 ] ][ $path[ 1 ] ];
            break;
        case 3:
            if (!isset($detailObject[ $path[ 0 ] ][ $path[ 1 ] ][ $path[ 2 ] ])
            ) {
                continue 2;
            }

            $newArray[ $path[ 0 ] ][ $path[ 1 ] ][ $path[ 2 ] ] = $detailObject[ $path[ 0 ] ][ $path[ 1 ] ][ $path[ 2 ] ];
            break;
    }
}

С параметром столбца,API обрабатывает данные и возвращает следующее:

[
  'col1' => [
    'sub1' => [
      'data2' => 'abc'
    ],
    'sub2' => [
      'other1' => true,
      'data3' => 987
    ]
]

Есть ли способ динамического создания этого вывода?

1 Ответ

0 голосов
/ 20 декабря 2018

Выполнение операций над вложенными структурами произвольной глубины почти всегда требует рекурсивной функции.

function filterPath($data, $path) {
    $key = array_shift($path);
    if( empty($path) ) {
        return [$key => $data[$key]];
    } else {
        return [$key => filterPath($data[$key], $path) ];
    }
}

function filterPaths($data, $paths) {
    $out = [];
    foreach($paths as $path) {
        $out = array_merge_recursive($out, filterPath($data, $path));
    }
    return $out;
}

$data = [
  'col1' => [
    'sub1' => [
      'data1' => false,
      'data2' => 'abc',
      'data3' => 123
    ],
    'sub2' => [
      'other1' => true,
      'data3' => 987
    ]
  ],
  'col2' => [
  ]
];

var_dump(
    filterPaths($data, [
        ['col1', 'sub1', 'data1'],
        ['col1', 'sub1', 'data3'],
        ['col1', 'sub2'],
        ['col2']
    ])
);

Вывод:

array(2) {
  ["col1"]=> array(2) {
    ["sub1"]=> array(2) {
      ["data1"]=> bool(false)
      ["data3"]=> int(123)
    }
    ["sub2"]=> array(2) {
      ["other1"]=> bool(true)
      ["data3"]=> int(987)
    }
  }
  ["col2"]=> array(0) {}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...